Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df10cfe641 | ||
|
|
09d3e8aabb | ||
|
|
f17411916f | ||
|
|
75583f67c5 | ||
|
|
bb745b0318 | ||
|
|
3834aeb73f | ||
|
|
aa09c079f6 | ||
|
|
3c586caba4 | ||
|
|
b05740048c | ||
|
|
2b5ed21207 | ||
|
|
acecb88efb | ||
|
|
990aaadc16 | ||
|
|
0c572b5947 | ||
|
|
3e7c294989 | ||
|
|
8a02156ac0 | ||
|
|
c4a75de0d8 | ||
|
|
db03bcdf8f | ||
|
|
dd5825c770 | ||
|
|
080f93f6de | ||
|
|
df931d95a3 | ||
|
|
9fd1a3c663 | ||
|
|
8a781d241c | ||
|
|
be4d610de1 | ||
|
|
736d3460d9 | ||
|
|
f844d70275 | ||
|
|
0c9cfefcd0 | ||
|
|
8ed187b0f5 | ||
|
|
e5bada81dc | ||
|
|
655f817033 | ||
|
|
ebff2ac9f2 | ||
|
|
5a7ffcf499 | ||
|
|
f8e117a7b7 | ||
|
|
c4054f0ac9 | ||
|
|
f7707141d6 | ||
|
|
c40c42fc10 | ||
|
|
6cad976078 | ||
|
|
c82f17e5d2 | ||
|
|
1054bde7fd | ||
|
|
9e23b91f3f | ||
|
|
ea6e064e42 | ||
|
|
cf0858f5b9 | ||
|
|
69b11a8412 | ||
|
|
55aad4254c | ||
|
|
73e1659378 | ||
|
|
98f3e8159e | ||
|
|
e8cff194fc | ||
|
|
f1de1b3b91 | ||
|
|
a134ab3012 | ||
|
|
5a84d7233b | ||
|
|
8fe0112568 | ||
|
|
3acaac5403 | ||
|
|
7dbac5a565 | ||
|
|
8fb4f4063f | ||
|
|
808718fb26 | ||
|
|
6dc8de315a | ||
|
|
afb9b08925 | ||
|
|
2bed034e64 | ||
|
|
2328bb6261 | ||
|
|
06357fa3f9 | ||
|
|
83f58288f9 | ||
|
|
b1d5f0f9e8 | ||
|
|
7142e4db37 | ||
|
|
281a079a62 | ||
|
|
0d638e6bad | ||
|
|
43a63feaca | ||
|
|
4aa6ffe28c | ||
|
|
2ce688ee2a | ||
|
|
4e967980a3 | ||
|
|
93edf07da8 | ||
|
|
a684bead92 | ||
|
|
dd06de2632 | ||
|
|
975f07df99 | ||
|
|
5fe6845d7c | ||
|
|
4aa844946d | ||
|
|
3220e3de31 | ||
|
|
26bba3c5f5 | ||
|
|
c82a5c38df | ||
|
|
9cfaf6eefc |
17
NEWS.md
17
NEWS.md
@@ -1,5 +1,22 @@
|
||||
# Changelog
|
||||
|
||||
## 8.0.0
|
||||
Released 2019-11-13
|
||||
|
||||
Breaking changes:
|
||||
- Schema change for "routes" in configuration file, each "router" is now an array instead of an object. See [`dd06de2`](https://github.com/CartoDB/Windshaft-cartodb/pull/1126/commits/dd06de2632661e19d64c9fbc2be0ba1a8059f54c) for more details.
|
||||
|
||||
Announcements:
|
||||
- Added validation to only allow "count" and "sum" aggregations in dataview overview.
|
||||
- Added mechanism to inject custom middlewares through configuration.
|
||||
- Stop requiring unused config properties: "base_url", "base_url_mapconfig", and "base_url_templated".
|
||||
- Upgraded cartodb-query-tables to version [0.7.0](https://github.com/CartoDB/node-cartodb-query-tables/blob/0.7.0/NEWS.md#version-0.7.0).
|
||||
- Be able to set a coherent TTL in Cache-Control header to expire all resources belonging to a map simultaneously.
|
||||
- When `cache buster` in request path is `0` set header `Last-Modified` to now, it avoids stalled content in 3rd party cache providers when they add `If-Modified-Since` header into the request.
|
||||
- Adding a logger to MapStore (#1134)
|
||||
- Qualify calls to cartodb extension so having it in the search_path isn't necessary.
|
||||
- Fix multiple DB login issues.
|
||||
|
||||
## 7.2.0
|
||||
Released 2019-09-30
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Create the config/environments/<env>.js files (there are .example files
|
||||
to start from). You can optionally use the ./configure script for this,
|
||||
see ```./configure --help``` to see available options.
|
||||
|
||||
Look at lib/cartodb/server_options.js for more on config
|
||||
Look at lib/cartodb/server-options.js for more on config
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
|
||||
14
app.js
14
app.js
@@ -6,7 +6,7 @@ var path = require('path');
|
||||
var fs = require('fs');
|
||||
var _ = require('underscore');
|
||||
var semver = require('semver');
|
||||
const setICUEnvVariable = require('./lib/cartodb/utils/icu_data_env_setter');
|
||||
const setICUEnvVariable = require('./lib/utils/icu-data-env-setter');
|
||||
|
||||
// jshint undef:false
|
||||
var log = console.log.bind(console);
|
||||
@@ -24,12 +24,12 @@ if (!semver.satisfies(nodejsVersion, engines.node)) {
|
||||
setICUEnvVariable();
|
||||
|
||||
var argv = require('yargs')
|
||||
.usage('Usage: $0 <environment> [options]')
|
||||
.usage('Usage: node $0 <environment> [options]')
|
||||
.help('h')
|
||||
.example(
|
||||
'$0 production -c /etc/sql-api/config.js',
|
||||
'start server in production environment with /etc/sql-api/config.js as config file'
|
||||
)
|
||||
'node $0 production -c /etc/windshaft-cartodb/config.js',
|
||||
'start server in production environment with /etc/windshaft-cartodb/config.js as config file'
|
||||
)
|
||||
.alias('h', 'help')
|
||||
.alias('c', 'config')
|
||||
.nargs('c', 1)
|
||||
@@ -105,8 +105,8 @@ global.logger = global.log4js.getLogger();
|
||||
|
||||
// Include cartodb_windshaft only _after_ the "global" variable is set
|
||||
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/28
|
||||
var cartodbWindshaft = require('./lib/cartodb/server');
|
||||
var serverOptions = require('./lib/cartodb/server_options');
|
||||
var cartodbWindshaft = require('./lib/server');
|
||||
var serverOptions = require('./lib/server-options');
|
||||
|
||||
var server = cartodbWindshaft(serverOptions);
|
||||
|
||||
|
||||
@@ -16,47 +16,41 @@ var config = {
|
||||
// Base URLs for the APIs
|
||||
//
|
||||
// See https://github.com/CartoDB/Windshaft-cartodb/wiki/Unified-Map-API
|
||||
//
|
||||
// Note: each entry corresponds with an express' router.
|
||||
// You must define at least one path. However, middlewares are optional.
|
||||
,routes: {
|
||||
v1: {
|
||||
api: [{
|
||||
paths: [
|
||||
'/api/v1',
|
||||
'/user/:user/api/v1',
|
||||
],
|
||||
// Base url for the Detached Maps API
|
||||
// "/api/v1/map" is the new API,
|
||||
map: {
|
||||
paths: [
|
||||
'/map',
|
||||
]
|
||||
},
|
||||
// Base url for the Templated Maps API
|
||||
// "/api/v1/map/named" is the new API,
|
||||
template: {
|
||||
paths: [
|
||||
'/map/named'
|
||||
]
|
||||
}
|
||||
},
|
||||
// For compatibility with versions up to 1.6.x
|
||||
v0: {
|
||||
paths: [
|
||||
'/tiles'
|
||||
// Optional: attach middlewares at the begining of the router
|
||||
// to perform custom operations.
|
||||
middlewares: [
|
||||
function noop () {
|
||||
return function noopMiddleware (req, res, next) {
|
||||
next();
|
||||
}
|
||||
}
|
||||
],
|
||||
// Base url for the Detached Maps API
|
||||
// "/tiles/layergroup" is for compatibility with versions up to 1.6.x
|
||||
map: {
|
||||
// "/api/v1/map" is the new API,
|
||||
map: [{
|
||||
paths: [
|
||||
'/layergroup'
|
||||
]
|
||||
},
|
||||
'/map',
|
||||
],
|
||||
middlewares: [] // Optional
|
||||
}],
|
||||
// Base url for the Templated Maps API
|
||||
// "/tiles/template" is for compatibility with versions up to 1.6.x
|
||||
template: {
|
||||
// "/api/v1/map/named" is the new API,
|
||||
template: [{
|
||||
paths: [
|
||||
'/template'
|
||||
]
|
||||
}
|
||||
}
|
||||
'/map/named'
|
||||
],
|
||||
middlewares: [] // Optional
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
// Resource URLs expose endpoints to request/retrieve metadata associated to Maps: dataviews, analysis node status.
|
||||
@@ -92,7 +86,8 @@ var config = {
|
||||
// If log_filename is given logs will be written
|
||||
// there, in append mode. Otherwise stdout is used (default).
|
||||
// Log file will be re-opened on receiving the HUP signal
|
||||
,log_filename: 'logs/node-windshaft.log'
|
||||
,log_filename: undefined
|
||||
,log_windshaft: true
|
||||
// Templated database username for authorized user
|
||||
// Supported labels: 'user_id' (read from redis)
|
||||
,postgres_auth_user: 'development_cartodb_user_<%= user_id %>'
|
||||
@@ -271,7 +266,7 @@ var config = {
|
||||
// If filename is given logs comming from analysis client will be written
|
||||
// there, in append mode. Otherwise 'log_filename' is used. Otherwise stdout is used (default).
|
||||
// Log file will be re-opened on receiving the HUP signal
|
||||
filename: 'logs/node-windshaft-analysis.log'
|
||||
filename: undefined
|
||||
},
|
||||
// Define max execution time in ms for analyses or tags
|
||||
// If analysis or tag are not found in redis this values will be used as default.
|
||||
|
||||
@@ -16,47 +16,41 @@ var config = {
|
||||
// Base URLs for the APIs
|
||||
//
|
||||
// See https://github.com/CartoDB/Windshaft-cartodb/wiki/Unified-Map-API
|
||||
//
|
||||
// Note: each entry corresponds with an express' router.
|
||||
// You must define at least one path. However, middlewares are optional.
|
||||
,routes: {
|
||||
v1: {
|
||||
api: [{
|
||||
paths: [
|
||||
'/api/v1',
|
||||
'/user/:user/api/v1',
|
||||
],
|
||||
// Base url for the Detached Maps API
|
||||
// "/api/v1/map" is the new API,
|
||||
map: {
|
||||
paths: [
|
||||
'/map',
|
||||
]
|
||||
},
|
||||
// Base url for the Templated Maps API
|
||||
// "/api/v1/map/named" is the new API,
|
||||
template: {
|
||||
paths: [
|
||||
'/map/named'
|
||||
]
|
||||
}
|
||||
},
|
||||
// For compatibility with versions up to 1.6.x
|
||||
v0: {
|
||||
paths: [
|
||||
'/tiles'
|
||||
// Optional: attach middlewares at the begining of the router
|
||||
// to perform custom operations.
|
||||
middlewares: [
|
||||
function noop () {
|
||||
return function noopMiddleware (req, res, next) {
|
||||
next();
|
||||
}
|
||||
}
|
||||
],
|
||||
// Base url for the Detached Maps API
|
||||
// "/tiles/layergroup" is for compatibility with versions up to 1.6.x
|
||||
map: {
|
||||
// "/api/v1/map" is the new API,
|
||||
map: [{
|
||||
paths: [
|
||||
'/layergroup'
|
||||
]
|
||||
},
|
||||
'/map',
|
||||
],
|
||||
middlewares: [] // Optional
|
||||
}],
|
||||
// Base url for the Templated Maps API
|
||||
// "/tiles/template" is for compatibility with versions up to 1.6.x
|
||||
template: {
|
||||
// "/api/v1/map/named" is the new API,
|
||||
template: [{
|
||||
paths: [
|
||||
'/template'
|
||||
]
|
||||
}
|
||||
}
|
||||
'/map/named'
|
||||
],
|
||||
middlewares: [] // Optional
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
// Resource URLs expose endpoints to request/retrieve metadata associated to Maps: dataviews, analysis node status.
|
||||
@@ -93,6 +87,7 @@ var config = {
|
||||
// there, in append mode. Otherwise stdout is used (default).
|
||||
// Log file will be re-opened on receiving the HUP signal
|
||||
,log_filename: 'logs/node-windshaft.log'
|
||||
,log_windshaft: true
|
||||
// Templated database username for authorized user
|
||||
// Supported labels: 'user_id' (read from redis)
|
||||
,postgres_auth_user: 'cartodb_user_<%= user_id %>'
|
||||
|
||||
@@ -16,47 +16,41 @@ var config = {
|
||||
// Base URLs for the APIs
|
||||
//
|
||||
// See https://github.com/CartoDB/Windshaft-cartodb/wiki/Unified-Map-API
|
||||
//
|
||||
// Note: each entry corresponds with an express' router.
|
||||
// You must define at least one path. However, middlewares are optional.
|
||||
,routes: {
|
||||
v1: {
|
||||
api: [{
|
||||
paths: [
|
||||
'/api/v1',
|
||||
'/user/:user/api/v1',
|
||||
],
|
||||
// Base url for the Detached Maps API
|
||||
// "/api/v1/map" is the new API,
|
||||
map: {
|
||||
paths: [
|
||||
'/map',
|
||||
]
|
||||
},
|
||||
// Base url for the Templated Maps API
|
||||
// "/api/v1/map/named" is the new API,
|
||||
template: {
|
||||
paths: [
|
||||
'/map/named'
|
||||
]
|
||||
}
|
||||
},
|
||||
// For compatibility with versions up to 1.6.x
|
||||
v0: {
|
||||
paths: [
|
||||
'/tiles'
|
||||
// Optional: attach middlewares at the begining of the router
|
||||
// to perform custom operations.
|
||||
middlewares: [
|
||||
function noop () {
|
||||
return function noopMiddleware (req, res, next) {
|
||||
next();
|
||||
}
|
||||
}
|
||||
],
|
||||
// Base url for the Detached Maps API
|
||||
// "/tiles/layergroup" is for compatibility with versions up to 1.6.x
|
||||
map: {
|
||||
// "/api/v1/map" is the new API,
|
||||
map: [{
|
||||
paths: [
|
||||
'/layergroup'
|
||||
]
|
||||
},
|
||||
'/map',
|
||||
],
|
||||
middlewares: [] // Optional
|
||||
}],
|
||||
// Base url for the Templated Maps API
|
||||
// "/tiles/template" is for compatibility with versions up to 1.6.x
|
||||
template: {
|
||||
// "/api/v1/map/named" is the new API,
|
||||
template: [{
|
||||
paths: [
|
||||
'/template'
|
||||
]
|
||||
}
|
||||
}
|
||||
'/map/named'
|
||||
],
|
||||
middlewares: [] // Optional
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
// Resource URLs expose endpoints to request/retrieve metadata associated to Maps: dataviews, analysis node status.
|
||||
@@ -93,6 +87,7 @@ var config = {
|
||||
// there, in append mode. Otherwise stdout is used (default).
|
||||
// Log file will be re-opened on receiving the HUP signal
|
||||
,log_filename: 'logs/node-windshaft.log'
|
||||
,log_windshaft: true
|
||||
// Templated database username for authorized user
|
||||
// Supported labels: 'user_id' (read from redis)
|
||||
,postgres_auth_user: 'cartodb_staging_user_<%= user_id %>'
|
||||
|
||||
@@ -16,47 +16,41 @@ var config = {
|
||||
// Base URLs for the APIs
|
||||
//
|
||||
// See https://github.com/CartoDB/Windshaft-cartodb/wiki/Unified-Map-API
|
||||
//
|
||||
// Note: each entry corresponds with an express' router.
|
||||
// You must define at least one path. However, middlewares are optional.
|
||||
,routes: {
|
||||
v1: {
|
||||
api: [{
|
||||
paths: [
|
||||
'/api/v1',
|
||||
'/user/:user/api/v1',
|
||||
],
|
||||
// Base url for the Detached Maps API
|
||||
// "/api/v1/map" is the new API,
|
||||
map: {
|
||||
paths: [
|
||||
'/map',
|
||||
]
|
||||
},
|
||||
// Base url for the Templated Maps API
|
||||
// "/api/v1/map/named" is the new API,
|
||||
template: {
|
||||
paths: [
|
||||
'/map/named'
|
||||
]
|
||||
}
|
||||
},
|
||||
// For compatibility with versions up to 1.6.x
|
||||
v0: {
|
||||
paths: [
|
||||
'/tiles'
|
||||
// Optional: attach middlewares at the begining of the router
|
||||
// to perform custom operations.
|
||||
middlewares: [
|
||||
function noop () {
|
||||
return function noopMiddleware (req, res, next) {
|
||||
next();
|
||||
}
|
||||
}
|
||||
],
|
||||
// Base url for the Detached Maps API
|
||||
// "/tiles/layergroup" is for compatibility with versions up to 1.6.x
|
||||
map: {
|
||||
// "/api/v1/map" is the new API,
|
||||
map: [{
|
||||
paths: [
|
||||
'/layergroup'
|
||||
]
|
||||
},
|
||||
'/map',
|
||||
],
|
||||
middlewares: [] // Optional
|
||||
}],
|
||||
// Base url for the Templated Maps API
|
||||
// "/tiles/template" is for compatibility with versions up to 1.6.x
|
||||
template: {
|
||||
// "/api/v1/map/named" is the new API,
|
||||
template: [{
|
||||
paths: [
|
||||
'/template'
|
||||
]
|
||||
}
|
||||
}
|
||||
'/map/named'
|
||||
],
|
||||
middlewares: [] // Optional
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
// Resource URLs expose endpoints to request/retrieve metadata associated to Maps: dataviews, analysis node status.
|
||||
@@ -93,6 +87,7 @@ var config = {
|
||||
// there, in append mode. Otherwise stdout is used (default).
|
||||
// Log file will be re-opened on receiving the HUP signal
|
||||
,log_filename: '/tmp/node-windshaft.log'
|
||||
,log_windshaft: true
|
||||
// Templated database username for authorized user
|
||||
// Supported labels: 'user_id' (read from redis)
|
||||
,postgres_auth_user: 'test_windshaft_cartodb_user_<%= user_id %>'
|
||||
|
||||
@@ -7,12 +7,12 @@ const cartodbRedis = require('cartodb-redis');
|
||||
|
||||
const windshaft = require('windshaft');
|
||||
|
||||
const PgConnection = require('../backends/pg_connection');
|
||||
const PgConnection = require('../backends/pg-connection');
|
||||
const AnalysisBackend = require('../backends/analysis');
|
||||
const AnalysisStatusBackend = require('../backends/analysis-status');
|
||||
const DataviewBackend = require('../backends/dataview');
|
||||
const TemplateMaps = require('../backends/template_maps.js');
|
||||
const PgQueryRunner = require('../backends/pg_query_runner');
|
||||
const TemplateMaps = require('../backends/template-maps');
|
||||
const PgQueryRunner = require('../backends/pg-query-runner');
|
||||
const StatsBackend = require('../backends/stats');
|
||||
const AuthBackend = require('../backends/auth');
|
||||
|
||||
@@ -23,12 +23,12 @@ const TablesExtentBackend = require('../backends/tables-extent');
|
||||
|
||||
const ClusterBackend = require('../backends/cluster');
|
||||
|
||||
const LayergroupAffectedTablesCache = require('../cache/layergroup_affected_tables');
|
||||
const SurrogateKeysCache = require('../cache/surrogate_keys_cache');
|
||||
const VarnishHttpCacheBackend = require('../cache/backend/varnish_http');
|
||||
const LayergroupAffectedTablesCache = require('../cache/layergroup-affected-tables');
|
||||
const SurrogateKeysCache = require('../cache/surrogate-keys-cache');
|
||||
const VarnishHttpCacheBackend = require('../cache/backend/varnish-http');
|
||||
const FastlyCacheBackend = require('../cache/backend/fastly');
|
||||
const NamedMapProviderCache = require('../cache/named_map_provider_cache');
|
||||
const NamedMapsCacheEntry = require('../cache/model/named_maps_entry');
|
||||
const NamedMapProviderCache = require('../cache/named-map-provider-cache');
|
||||
const NamedMapsCacheEntry = require('../cache/model/named-maps-entry');
|
||||
const NamedMapProviderReporter = require('../stats/reporter/named-map-provider');
|
||||
|
||||
const SqlWrapMapConfigAdapter = require('../models/mapconfig/adapter/sql-wrap-mapconfig-adapter');
|
||||
@@ -83,9 +83,13 @@ module.exports = class ApiRouter {
|
||||
const metadataBackend = cartodbRedis({ pool: redisPool });
|
||||
const pgConnection = new PgConnection(metadataBackend);
|
||||
|
||||
const windshaftLogger = environmentOptions.log_windshaft && global.log4js ?
|
||||
global.log4js.getLogger('[windshaft]') :
|
||||
null;
|
||||
const mapStore = new windshaft.storage.MapStore({
|
||||
pool: redisPool,
|
||||
expire_time: serverOptions.grainstore.default_layergroup_ttl
|
||||
expire_time: serverOptions.grainstore.default_layergroup_ttl,
|
||||
logger: windshaftLogger
|
||||
});
|
||||
|
||||
const rendererFactory = createRendererFactory({ redisPool, serverOptions, environmentOptions });
|
||||
@@ -196,16 +200,17 @@ module.exports = class ApiRouter {
|
||||
this.templateRouter = new TemplateRouter({ collaborators });
|
||||
}
|
||||
|
||||
register (app) {
|
||||
route (app, routes) {
|
||||
// FIXME: we need a better way to reset cache while running tests
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
app.layergroupAffectedTablesCache = this.layergroupAffectedTablesCache;
|
||||
}
|
||||
|
||||
Object.keys(this.serverOptions.routes).forEach(apiVersion => {
|
||||
const routes = this.serverOptions.routes[apiVersion];
|
||||
|
||||
routes.forEach(route => {
|
||||
const apiRouter = router({ mergeParams: true });
|
||||
const { paths, middlewares = [] } = route;
|
||||
|
||||
middlewares.forEach(middleware => apiRouter.use(middleware()));
|
||||
|
||||
apiRouter.use(logger(this.serverOptions));
|
||||
apiRouter.use(initializeStatusCode());
|
||||
@@ -219,16 +224,14 @@ module.exports = class ApiRouter {
|
||||
apiRouter.use(cors());
|
||||
apiRouter.use(user());
|
||||
|
||||
this.templateRouter.register(apiRouter, routes.template.paths);
|
||||
this.mapRouter.register(apiRouter, routes.map.paths);
|
||||
this.templateRouter.route(apiRouter, route.template);
|
||||
this.mapRouter.route(apiRouter, route.map);
|
||||
|
||||
apiRouter.use(sendResponse());
|
||||
apiRouter.use(syntaxError());
|
||||
apiRouter.use(errorMiddleware());
|
||||
|
||||
const apiPaths = routes.paths;
|
||||
|
||||
apiPaths.forEach(path => app.use(path, apiRouter));
|
||||
paths.forEach(path => app.use(path, apiRouter));
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -283,7 +286,7 @@ function createSurrogateKeysCacheBackends(serverOptions) {
|
||||
return cacheBackends;
|
||||
}
|
||||
|
||||
const timeoutErrorTilePath = __dirname + '/../../../assets/render-timeout-fallback.png';
|
||||
const timeoutErrorTilePath = __dirname + '/../../assets/render-timeout-fallback.png';
|
||||
const timeoutErrorTile = require('fs').readFileSync(timeoutErrorTilePath, {encoding: null});
|
||||
|
||||
function createRendererFactory ({ redisPool, serverOptions, environmentOptions }) {
|
||||
@@ -17,7 +17,7 @@ module.exports = class AnalysesController {
|
||||
this.userLimitsBackend = userLimitsBackend;
|
||||
}
|
||||
|
||||
register (mapRouter) {
|
||||
route (mapRouter) {
|
||||
mapRouter.get('/analyses/catalog', this.middlewares());
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ module.exports = class AnalysisLayergroupController {
|
||||
this.authBackend = authBackend;
|
||||
}
|
||||
|
||||
register (mapRouter) {
|
||||
route (mapRouter) {
|
||||
mapRouter.get('/:token/analysis/node/:nodeId', this.middlewares());
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ module.exports = class AnonymousMapController {
|
||||
this.layergroupMetadata = layergroupMetadata;
|
||||
}
|
||||
|
||||
register (mapRouter) {
|
||||
route (mapRouter) {
|
||||
mapRouter.options('/');
|
||||
mapRouter.get('/', this.middlewares());
|
||||
mapRouter.post('/', this.middlewares());
|
||||
@@ -32,7 +32,7 @@ module.exports = class AttributesLayergroupController {
|
||||
this.surrogateKeysCache = surrogateKeysCache;
|
||||
}
|
||||
|
||||
register (mapRouter) {
|
||||
route (mapRouter) {
|
||||
mapRouter.get('/:token/:layer/attributes/:fid', this.middlewares());
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ module.exports = class AggregatedFeaturesLayergroupController {
|
||||
this.surrogateKeysCache = surrogateKeysCache;
|
||||
}
|
||||
|
||||
register (mapRouter) {
|
||||
route (mapRouter) {
|
||||
mapRouter.get('/:token/:layer/:z/cluster/:clusterId', this.middlewares());
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ module.exports = class DataviewLayergroupController {
|
||||
this.surrogateKeysCache = surrogateKeysCache;
|
||||
}
|
||||
|
||||
register (mapRouter) {
|
||||
route (mapRouter) {
|
||||
// Undocumented/non-supported API endpoint methods.
|
||||
// Use at your own peril.
|
||||
|
||||
@@ -126,19 +126,25 @@ module.exports = class MapRouter {
|
||||
);
|
||||
}
|
||||
|
||||
register (apiRouter, mapPaths) {
|
||||
route (apiRouter, routes) {
|
||||
const mapRouter = router({ mergeParams: true });
|
||||
|
||||
this.analysisLayergroupController.register(mapRouter);
|
||||
this.attributesLayergroupController.register(mapRouter);
|
||||
this.dataviewLayergroupController.register(mapRouter);
|
||||
this.previewLayergroupController.register(mapRouter);
|
||||
this.tileLayergroupController.register(mapRouter);
|
||||
this.anonymousMapController.register(mapRouter);
|
||||
this.previewTemplateController.register(mapRouter);
|
||||
this.analysesController.register(mapRouter);
|
||||
this.clusteredFeaturesLayergroupController.register(mapRouter);
|
||||
routes.forEach(route => {
|
||||
const { paths, middlewares = [] } = route;
|
||||
|
||||
mapPaths.forEach(path => apiRouter.use(path, mapRouter));
|
||||
middlewares.forEach(middleware => mapRouter.use(middleware()));
|
||||
|
||||
this.analysisLayergroupController.route(mapRouter);
|
||||
this.attributesLayergroupController.route(mapRouter);
|
||||
this.dataviewLayergroupController.route(mapRouter);
|
||||
this.previewLayergroupController.route(mapRouter);
|
||||
this.tileLayergroupController.route(mapRouter);
|
||||
this.anonymousMapController.route(mapRouter);
|
||||
this.previewTemplateController.route(mapRouter);
|
||||
this.analysesController.route(mapRouter);
|
||||
this.clusteredFeaturesLayergroupController.route(mapRouter);
|
||||
|
||||
paths.forEach(path => apiRouter.use(path, mapRouter));
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -35,7 +35,7 @@ module.exports = class PreviewLayergroupController {
|
||||
this.surrogateKeysCache = surrogateKeysCache;
|
||||
}
|
||||
|
||||
register (mapRouter) {
|
||||
route (mapRouter) {
|
||||
mapRouter.get('/static/center/:token/:z/:lat/:lng/:width/:height.:format', this.middlewares({
|
||||
validateZoom: true,
|
||||
previewType: 'centered'
|
||||
@@ -46,7 +46,7 @@ module.exports = class PreviewTemplateController {
|
||||
this.userLimitsBackend = userLimitsBackend;
|
||||
}
|
||||
|
||||
register (mapRouter) {
|
||||
route (mapRouter) {
|
||||
mapRouter.get('/static/named/:template_id/:width/:height.:format', this.middlewares());
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ module.exports = class TileLayergroupController {
|
||||
this.surrogateKeysCache = surrogateKeysCache;
|
||||
}
|
||||
|
||||
register (mapRouter) {
|
||||
route (mapRouter) {
|
||||
// REGEXP: doesn't match with `val`
|
||||
const not = (val) => `(?!${val})([^\/]+?)`;
|
||||
|
||||
@@ -1,14 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
const ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365;
|
||||
const FIVE_MINUTES_IN_SECONDS = 60 * 5;
|
||||
const ONE_MINUTE_IN_SECONDS = 60;
|
||||
const THREE_MINUTE_IN_SECONDS = 60 * 3;
|
||||
const FIVE_MINUTES_IN_SECONDS = ONE_MINUTE_IN_SECONDS * 5;
|
||||
const TEN_MINUTES_IN_SECONDS = ONE_MINUTE_IN_SECONDS * 10;
|
||||
const FIFTEEN_MINUTES_IN_SECONDS = ONE_MINUTE_IN_SECONDS * 15;
|
||||
const THIRTY_MINUTES_IN_SECONDS = ONE_MINUTE_IN_SECONDS * 30;
|
||||
const ONE_HOUR_IN_SECONDS = ONE_MINUTE_IN_SECONDS * 60;
|
||||
const ONE_YEAR_IN_SECONDS = ONE_HOUR_IN_SECONDS * 24 * 365;
|
||||
|
||||
const FALLBACK_TTL = global.environment.varnish.fallbackTtl || FIVE_MINUTES_IN_SECONDS;
|
||||
|
||||
const validFallbackTTL = [
|
||||
ONE_MINUTE_IN_SECONDS,
|
||||
THREE_MINUTE_IN_SECONDS,
|
||||
FIVE_MINUTES_IN_SECONDS,
|
||||
TEN_MINUTES_IN_SECONDS,
|
||||
FIFTEEN_MINUTES_IN_SECONDS,
|
||||
THIRTY_MINUTES_IN_SECONDS,
|
||||
ONE_HOUR_IN_SECONDS
|
||||
];
|
||||
|
||||
module.exports = function setCacheControlHeader ({
|
||||
ttl = ONE_YEAR_IN_SECONDS,
|
||||
fallbackTtl = FALLBACK_TTL,
|
||||
revalidate = false
|
||||
} = {}) {
|
||||
if (!validFallbackTTL.includes(fallbackTtl)) {
|
||||
const message = [
|
||||
'Invalid fallback TTL value for Cache-Control header.',
|
||||
`Got ${fallbackTtl}, expected ${validFallbackTTL.join(', ')}`
|
||||
].join(' ');
|
||||
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
return function setCacheControlHeaderMiddleware (req, res, next) {
|
||||
if (req.method !== 'GET') {
|
||||
return next();
|
||||
@@ -27,7 +53,7 @@ module.exports = function setCacheControlHeader ({
|
||||
if (everyAffectedTableCanBeInvalidated(affectedTables)) {
|
||||
directives.push(`max-age=${ttl}`);
|
||||
} else {
|
||||
directives.push(`max-age=${fallbackTtl}`);
|
||||
directives.push(`max-age=${computeNextTTL({ ttlInSeconds: fallbackTtl })}`);
|
||||
}
|
||||
|
||||
if (revalidate) {
|
||||
@@ -49,3 +75,11 @@ function everyAffectedTableCanBeInvalidated (affectedTables) {
|
||||
affectedTables.getTables(skipNotUpdatedAtTables, skipAnalysisCachedTables)
|
||||
.every(table => table.updated_at !== null);
|
||||
}
|
||||
|
||||
function computeNextTTL ({ ttlInSeconds } = {}) {
|
||||
const nowInSeconds = Math.ceil(Date.now() / 1000);
|
||||
const secondsAfterPreviousTTLStep = nowInSeconds % ttlInSeconds;
|
||||
const secondsToReachTheNextTTLStep = ttlInSeconds - secondsAfterPreviousTTLStep;
|
||||
|
||||
return secondsToReachTheNextTTLStep;
|
||||
}
|
||||
@@ -10,7 +10,9 @@ module.exports = function setLastModifiedHeader () {
|
||||
|
||||
if (cache_buster) {
|
||||
const cacheBuster = parseInt(cache_buster, 10);
|
||||
const lastModifiedDate = Number.isFinite(cacheBuster) ? new Date(cacheBuster) : new Date();
|
||||
const lastModifiedDate = Number.isFinite(cacheBuster) && cacheBuster !== 0 ?
|
||||
new Date(cacheBuster) :
|
||||
new Date();
|
||||
|
||||
res.set('Last-Modified', lastModifiedDate.toUTCString());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const Profiler = require('../../stats/profiler_proxy');
|
||||
const Profiler = require('../../stats/profiler-proxy');
|
||||
const debug = require('debug')('windshaft:cartodb:stats');
|
||||
const onHeaders = require('on-headers');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const NamedMapsCacheEntry = require('../../cache/model/named_maps_entry');
|
||||
const NamedMapsCacheEntry = require('../../cache/model/named-maps-entry');
|
||||
const NamedMapMapConfigProvider = require('../../models/mapconfig/provider/named-map-provider');
|
||||
|
||||
module.exports = function setSurrogateKeyHeader ({ surrogateKeysCache }) {
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const CdbRequest = require('../../models/cdb_request');
|
||||
const CdbRequest = require('../../models/cdb-request');
|
||||
|
||||
module.exports = function user () {
|
||||
const cdbRequest = new CdbRequest();
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const timeoutErrorVectorTile = fs.readFileSync(__dirname + '/../../../../assets/render-timeout-fallback.mvt');
|
||||
const timeoutErrorVectorTile = fs.readFileSync(__dirname + '/../../../assets/render-timeout-fallback.mvt');
|
||||
|
||||
module.exports = function vectorError() {
|
||||
return function vectorErrorMiddleware(err, req, res, next) {
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const { templateName } = require('../../backends/template_maps');
|
||||
const { templateName } = require('../../backends/template-maps');
|
||||
const credentials = require('../middlewares/credentials');
|
||||
const rateLimit = require('../middlewares/rate-limit');
|
||||
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
|
||||
@@ -18,7 +18,7 @@ module.exports = class AdminTemplateController {
|
||||
this.userLimitsBackend = userLimitsBackend;
|
||||
}
|
||||
|
||||
register (templateRouter) {
|
||||
route (templateRouter) {
|
||||
templateRouter.options(`/:template_id`);
|
||||
|
||||
templateRouter.post('/', this.middlewares({
|
||||
@@ -63,7 +63,7 @@ module.exports = class NamedMapController {
|
||||
this.layergroupMetadata = layergroupMetadata;
|
||||
}
|
||||
|
||||
register (templateRouter) {
|
||||
route (templateRouter) {
|
||||
templateRouter.get('/:template_id/jsonp', this.middlewares());
|
||||
templateRouter.post('/:template_id', this.middlewares());
|
||||
}
|
||||
@@ -54,13 +54,19 @@ module.exports = class TemplateRouter {
|
||||
);
|
||||
}
|
||||
|
||||
register (apiRouter, templatePaths) {
|
||||
route (apiRouter, routes) {
|
||||
const templateRouter = router({ mergeParams: true });
|
||||
|
||||
this.namedMapController.register(templateRouter);
|
||||
this.tileTemplateController.register(templateRouter);
|
||||
this.adminTemplateController.register(templateRouter);
|
||||
routes.forEach(route => {
|
||||
const { paths, middlewares = [] } = route;
|
||||
|
||||
templatePaths.forEach(path => apiRouter.use(path, templateRouter));
|
||||
middlewares.forEach(middleware => templateRouter.use(middleware()));
|
||||
|
||||
this.namedMapController.route(templateRouter);
|
||||
this.tileTemplateController.route(templateRouter);
|
||||
this.adminTemplateController.route(templateRouter);
|
||||
|
||||
paths.forEach(path => apiRouter.use(path, templateRouter));
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -31,7 +31,7 @@ module.exports = class TileTemplateController {
|
||||
this.userLimitsBackend = userLimitsBackend;
|
||||
}
|
||||
|
||||
register (templateRouter) {
|
||||
route (templateRouter) {
|
||||
templateRouter.get('/:template_id/:layer/:z/:x/:y.(:format)', this.middlewares());
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ var BBoxFilter = require('../models/filter/bbox');
|
||||
var DataviewFactory = require('../models/dataview/factory');
|
||||
var DataviewFactoryWithOverviews = require('../models/dataview/overviews/factory');
|
||||
const dbParamsFromReqParams = require('../utils/database-params');
|
||||
var OverviewsQueryRewriter = require('../utils/overviews_query_rewriter');
|
||||
var OverviewsQueryRewriter = require('../utils/overviews-query-rewriter');
|
||||
var overviewsQueryRewriter = new OverviewsQueryRewriter({
|
||||
zoom_level: 'CDB_ZoomFromScale(!scale_denominator!)'
|
||||
zoom_level: 'cartodb.CDB_ZoomFromScale(!scale_denominator!)'
|
||||
});
|
||||
|
||||
var dot = require('dot');
|
||||
@@ -12,9 +12,9 @@ OverviewsMetadataBackend.prototype.getOverviewsMetadata = function (username, sq
|
||||
// FIXME: Currently using internal function _cdb_schema_name
|
||||
// CDB_Overviews should provide the schema information directly.
|
||||
const query = `
|
||||
SELECT *, _cdb_schema_name(base_table)
|
||||
FROM CDB_Overviews(
|
||||
CDB_QueryTablesText($windshaft$${queryUtils.substituteDummyTokens(sql)}$windshaft$)
|
||||
SELECT *, cartodb._cdb_schema_name(base_table)
|
||||
FROM cartodb.CDB_Overviews(
|
||||
cartodb.CDB_QueryTablesText($windshaft$${queryUtils.substituteDummyTokens(sql)}$windshaft$)
|
||||
);
|
||||
`;
|
||||
this.pgQueryRunner.run(username, query, function handleOverviewsRows(err, rows) {
|
||||
@@ -3,6 +3,7 @@
|
||||
var PSQL = require('cartodb-psql');
|
||||
var _ = require('underscore');
|
||||
const debug = require('debug')('cachechan');
|
||||
const dbParamsFromReqParams = require('../utils/database-params');
|
||||
|
||||
function PgConnection(metadataBackend) {
|
||||
this.metadataBackend = metadataBackend;
|
||||
@@ -124,14 +125,7 @@ PgConnection.prototype.getConnection = function(username, callback) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(err, new PSQL({
|
||||
user: databaseParams.dbuser,
|
||||
pass: databaseParams.dbpass,
|
||||
host: databaseParams.dbhost,
|
||||
port: databaseParams.dbport,
|
||||
dbname: databaseParams.dbname
|
||||
}));
|
||||
|
||||
return callback(err, new PSQL(dbParamsFromReqParams(databaseParams)));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var PSQL = require('cartodb-psql');
|
||||
const dbParamsFromReqParams = require('../utils/database-params');
|
||||
|
||||
function PgQueryRunner(pgConnection) {
|
||||
this.pgConnection = pgConnection;
|
||||
@@ -22,13 +23,7 @@ PgQueryRunner.prototype.run = function(username, query, callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
const psql = new PSQL({
|
||||
user: databaseParams.dbuser,
|
||||
pass: databaseParams.dbpass,
|
||||
host: databaseParams.dbhost,
|
||||
port: databaseParams.dbport,
|
||||
dbname: databaseParams.dbname
|
||||
});
|
||||
const psql = new PSQL(dbParamsFromReqParams(databaseParams));
|
||||
|
||||
psql.query(query, function (err, resultSet) {
|
||||
resultSet = resultSet || {};
|
||||
@@ -3,7 +3,7 @@
|
||||
const LruCache = require('lru-cache');
|
||||
|
||||
const NamedMapMapConfigProvider = require('../models/mapconfig/provider/named-map-provider');
|
||||
const { templateName } = require('../backends/template_maps');
|
||||
const { templateName } = require('../backends/template-maps');
|
||||
|
||||
const TEN_MINUTES_IN_MILLISECONDS = 1000 * 60 * 10;
|
||||
const ACTIONS = ['update', 'delete'];
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const dataviews = require('./');
|
||||
const dataviews = require('.');
|
||||
|
||||
module.exports = class DataviewFactory {
|
||||
static get dataviews() {
|
||||
@@ -94,6 +94,8 @@ var CATEGORIES_LIMIT = 6;
|
||||
function Aggregation(query, options, queryRewriter, queryRewriteData, params, queries) {
|
||||
BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params, queries);
|
||||
|
||||
this._checkOptions(options);
|
||||
|
||||
this.query = query;
|
||||
this.queries = queries;
|
||||
this.column = options.column;
|
||||
@@ -219,6 +221,26 @@ var aggregationFnQueryTpl = {
|
||||
sum: dot.template('sum({{=it._aggregationColumn}}*_feature_count)')
|
||||
};
|
||||
|
||||
const VALID_OPERATIONS = {
|
||||
count: [],
|
||||
sum: ['aggregationColumn']
|
||||
};
|
||||
|
||||
Aggregation.prototype._checkOptions = function (options) {
|
||||
if (!VALID_OPERATIONS[options.aggregation]) {
|
||||
throw new Error(`Aggregation does not support '${options.aggregation}' operation in dataview overview options`);
|
||||
}
|
||||
|
||||
const requiredOptions = VALID_OPERATIONS[options.aggregation];
|
||||
const missingOptions = requiredOptions.filter(requiredOption => !options.hasOwnProperty(requiredOption));
|
||||
|
||||
if (missingOptions.length > 0) {
|
||||
throw new Error(
|
||||
`Aggregation '${options.aggregation}' is missing some options for overview: ${missingOptions.join(',')}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Aggregation.prototype.getAggregationSql = function() {
|
||||
return aggregationFnQueryTpl[this.aggregation]({
|
||||
_aggregationFn: this.aggregation,
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var parentFactory = require('../factory');
|
||||
var dataviews = require('./');
|
||||
var dataviews = require('.');
|
||||
|
||||
function OverviewsDataviewFactory(queryRewriter, queryRewriteData, options) {
|
||||
this.queryRewriter = queryRewriter;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user