diff --git a/lib/cartodb/controllers/named_maps.js b/lib/cartodb/controllers/named_maps.js index 7cdd6acd..d7466046 100644 --- a/lib/cartodb/controllers/named_maps.js +++ b/lib/cartodb/controllers/named_maps.js @@ -11,7 +11,7 @@ var cors = require('../middleware/cors'); var TablesCacheEntry = require('../cache/model/database_tables_entry'); function NamedMapsController(app, authApi, pgConnection, namedMapProviderCache, tileBackend, previewBackend, - surrogateKeysCache, tablesExtentApi) { + surrogateKeysCache, tablesExtentApi, metadataBackend) { BaseController.call(this, authApi, pgConnection); this.app = app; @@ -20,6 +20,7 @@ function NamedMapsController(app, authApi, pgConnection, namedMapProviderCache, this.previewBackend = previewBackend; this.surrogateKeysCache = surrogateKeysCache; this.tablesExtentApi = tablesExtentApi; + this.metadataBackend = metadataBackend; } util.inherits(NamedMapsController, BaseController); @@ -156,6 +157,19 @@ NamedMapsController.prototype.staticMap = function(req, res) { namedMapProvider, format, width, height, imageOpts.bounds, this); } }, + function incrementMapViews(err, image, headers, stats) { + assert.ifError(err); + + var next = this; + namedMapProvider.getMapConfig(function(mapConfigErr, mapConfig) { + self.metadataBackend.incMapviewCount(cdbUser, mapConfig.obj().stat_tag, function(sErr) { + if (err) { + global.logger.log("ERROR: failed to increment mapview count for user '%s': %s", cdbUser, sErr); + } + next(err, image, headers, stats); + }); + }); + }, function handleImage(err, image, headers, stats) { if (req.profiler) { req.profiler.done('render-' + format); diff --git a/lib/cartodb/server.js b/lib/cartodb/server.js index 672c1f6b..0e603adb 100644 --- a/lib/cartodb/server.js +++ b/lib/cartodb/server.js @@ -197,7 +197,8 @@ module.exports = function(serverOptions) { tileBackend, previewBackend, surrogateKeysCache, - tablesExtentApi + tablesExtentApi, + metadataBackend ).register(app); new controller.NamedMapsAdmin(templateMaps, authApi, pgConnection).register(app); diff --git a/test/acceptance/named_maps_authentication.js b/test/acceptance/named_maps_authentication.js index 5e100941..f984391c 100644 --- a/test/acceptance/named_maps_authentication.js +++ b/test/acceptance/named_maps_authentication.js @@ -261,7 +261,7 @@ describe('named maps authentication', function() { assert.equal(img.height(), 480); test_helper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, tokenAuthTemplateName).key()); - done(); + test_helper.deleteRedisKeys({'user:localhost:mapviews:global': 5}, done); }); }); }); diff --git a/test/acceptance/named_maps_static_view.js b/test/acceptance/named_maps_static_view.js index f8d64212..f091c213 100644 --- a/test/acceptance/named_maps_static_view.js +++ b/test/acceptance/named_maps_static_view.js @@ -1,4 +1,4 @@ -require('../support/test_helper'); +var testHelper = require('../support/test_helper'); var RedisPool = require('redis-mpool'); var assert = require('../support/assert'); @@ -77,7 +77,9 @@ describe('named maps static view', function() { var server = new CartodbWindshaft(serverOptions); assert.response(server, requestOptions, expectedResponse, function (res, err) { - return callback(err, mapnik.Image.fromBytes(new Buffer(res.body, 'binary'))); + testHelper.deleteRedisKeys({'user:localhost:mapviews:global': 5}, function() { + return callback(err, mapnik.Image.fromBytes(new Buffer(res.body, 'binary'))); + }); }); } diff --git a/test/acceptance/named_maps_stats.js b/test/acceptance/named_maps_stats.js new file mode 100644 index 00000000..9813a402 --- /dev/null +++ b/test/acceptance/named_maps_stats.js @@ -0,0 +1,110 @@ +var test_helper = require('../support/test_helper'); +var RedisPool = require('redis-mpool'); +var querystring = require('querystring'); + +var assert = require('../support/assert'); +var mapnik = require('windshaft').mapnik; +var CartodbWindshaft = require(__dirname + '/../../lib/cartodb/server'); +var serverOptions = require(__dirname + '/../../lib/cartodb/server_options'); +var server = new CartodbWindshaft(serverOptions); +var TemplateMaps = require('../../lib/cartodb/backends/template_maps.js'); +var NamedMapsCacheEntry = require('../../lib/cartodb/cache/model/named_maps_entry'); + +describe('named maps preview stats', function() { + var redisPool = new RedisPool(global.environment.redis); + + var templateMaps = new TemplateMaps(redisPool, { + max_user_templates: global.environment.maxUserTemplates + }); + + var username = 'localhost'; + + var statTag = 'wadus_viz'; + var templateName = 'with_stats'; + var template = { + version: '0.0.1', + name: templateName, + auth: { + method: 'open' + }, + "placeholders": { + "color": { + "type": "css_color", + "default": "#cc3300" + } + }, + layergroup: { + stat_tag: statTag, + layers: [ + { + type: 'cartodb', + options: { + sql: 'select 1 cartodb_id, null::geometry the_geom_webmercator', + cartocss: '#layer { marker-fill: <%= color %>; }', + cartocss_version: '2.3.0' + } + } + ] + } + }; + + + beforeEach(function (done) { + templateMaps.addTemplate(username, template, done); + }); + + afterEach(function (done) { + templateMaps.delTemplate(username, templateName, done); + }); + + function getStaticMap(name, options, callback) { + + var url = '/api/v1/map/static/named/' + name + '/640/480.png'; + if (options.params) { + url = url + '?' + querystring.stringify(options.params); + } + var requestOptions = { + url: url, + method: 'GET', + headers: { + host: username + }, + encoding: 'binary' + }; + + var statusCode = options.status || 200; + + var expectedResponse = { + status: statusCode, + headers: { + 'Content-Type': statusCode === 200 ? 'image/png' : 'application/json; charset=utf-8' + } + }; + + assert.response(server, + requestOptions, + expectedResponse, + function (res, err) { + var img; + if (!err && res.headers['content-type'] === 'image/png') { + img = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); + } + return callback(err, res, img); + } + ); + } + + it('should return 200 if properly authorized', function(done) { + getStaticMap(templateName, { params: { auth_token: 'valid1' } }, function(err, res, img) { + assert.ok(!err); + + assert.equal(img.width(), 640); + assert.equal(img.height(), 480); + + test_helper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, templateName).key()); + var redisKeysToDelete = { 'user:localhost:mapviews:global': 5 }; + redisKeysToDelete['user:localhost:mapviews:stat_tag:' + statTag] = 5; + test_helper.deleteRedisKeys(redisKeysToDelete, done); + }); + }); +});