diff --git a/lib/cartodb/backends/template_maps.js b/lib/cartodb/backends/template_maps.js index 75a482fe..41e655bd 100644 --- a/lib/cartodb/backends/template_maps.js +++ b/lib/cartodb/backends/template_maps.js @@ -1,7 +1,5 @@ -var assert = require('assert'); var crypto = require('crypto'); var debug = require('debug')('windshaft:templates'); -var step = require('step'); var _ = require('underscore'); var dot = require('dot'); @@ -69,27 +67,19 @@ TemplateMaps.prototype._userTemplateLimit = function() { * @param callback - function to pass results too. */ TemplateMaps.prototype._redisCmd = function(redisFunc, redisArgs, callback) { - var redisClient; - var that = this; - var db = that.db_signatures; + this.redis_pool.acquire(this.db_signatures, (err, redisClient) => { + if (err) { + return callback(err); + } - step( - function getRedisClient() { - that.redis_pool.acquire(db, this); - }, - function executeQuery(err, data) { - assert.ifError(err); - redisClient = data; - redisArgs.push(this); - redisClient[redisFunc.toUpperCase()].apply(redisClient, redisArgs); - }, - function releaseRedisClient(err, data) { - if ( ! _.isUndefined(redisClient) ) { - that.redis_pool.release(db, redisClient); - } - callback(err, data); - } - ); + redisClient[redisFunc.toUpperCase()](...redisArgs, (err, data) => { + this.redis_pool.release(this.db_signatures, redisClient); + if (err) { + return callback(err); + } + return callback(null, data); + }); + }); }; var _reValidNameIdentifier = /^[a-z0-9][0-9a-z_\-]*$/i; @@ -184,6 +174,37 @@ function templateDefaults(template) { }); } +/** + * Checks if the if the user reaches the templetes limit + * + * @param userTemplatesKey user templat key in Redis + * @param owner cartodb username of the template owner + * @param callback returns error if the user reaches the limit + */ +TemplateMaps.prototype._checkUserTemplatesLimit = function(userTemplatesKey, owner, callback) { + const limit = this._userTemplateLimit(); + + if(!limit) { + return callback(); + } + + this._redisCmd('HLEN', [userTemplatesKey], (err, numberOfTemplates) => { + if (err) { + return callback(err); + } + + if (numberOfTemplates >= limit) { + const limitReachedError = new Error( + `User '${owner}' reached limit on number of templates (${numberOfTemplates}/${limit})` + ); + limitReachedError.http_status = 409; + return callback(limitReachedError); + } + + return callback(); + }); +}; + //--------------- PUBLIC API ------------------------------------- // Add a template @@ -199,52 +220,41 @@ function templateDefaults(template) { // Return template identifier (only valid for given user) // TemplateMaps.prototype.addTemplate = function(owner, template, callback) { - var self = this; - template = templateDefaults(template); var invalidError = this._checkInvalidTemplate(template); - if ( invalidError ) { + if (invalidError) { return callback(invalidError); } - var templateName = template.name; - var userTemplatesKey = this.key_usr_tpl({ owner:owner }); - var limit = this._userTemplateLimit(); + var userTemplatesKey = this.key_usr_tpl({ owner }); - step( - function checkLimit() { - if ( ! limit ) { - return 0; - } - self._redisCmd('HLEN', [ userTemplatesKey ], this); - }, - function installTemplateIfDoesNotExist(err, numberOfTemplates) { - assert.ifError(err); - if ( limit && numberOfTemplates >= limit ) { - var limitReachedError = new Error("User '" + owner + "' reached limit on number of templates (" + - numberOfTemplates + "/" + limit + ")"); - limitReachedError.http_status = 409; - throw limitReachedError; - } - self._redisCmd('HSETNX', [ userTemplatesKey, templateName, JSON.stringify(template) ], this); - }, - function validateInstallation(err, wasSet) { - assert.ifError(err); - if ( ! wasSet ) { - throw new Error("Template '" + templateName + "' of user '" + owner + "' already exists"); - } - - return true; - }, - function finish(err) { - if (!err) { - self.emit('add', owner, templateName, template); - } - - callback(err, templateName, template); + this._checkUserTemplatesLimit(userTemplatesKey, owner, err => { + if (err) { + return callback(err); } - ); + + let templateString; + try { + templateString = JSON.stringify(template); + } catch (error) { + return callback(error); + } + + this._redisCmd('HSETNX', [userTemplatesKey, template.name, templateString], (err, wasSet) => { + if (err) { + return callback(err); + } + + if (!wasSet) { + var templateExistsError = new Error(`Template '${template.name}' of user '${owner}' already exists`); + return callback(templateExistsError); + } + + this.emit('add', owner, template.name, template); + return callback(null, template.name, template); + }); + }); }; // Delete a template @@ -257,26 +267,18 @@ TemplateMaps.prototype.addTemplate = function(owner, template, callback) { // @param callback function(err) // TemplateMaps.prototype.delTemplate = function(owner, tpl_id, callback) { - var self = this; - step( - function deleteTemplate() { - self._redisCmd('HDEL', [ self.key_usr_tpl({ owner:owner }), tpl_id ], this); - }, - function handleDeletion(err, deleted) { - assert.ifError(err); - if (!deleted) { - throw new Error("Template '" + tpl_id + "' of user '" + owner + "' does not exist"); - } - return true; - }, - function finish(err) { - if (!err) { - self.emit('delete', owner, tpl_id); - } - - callback(err); + this._redisCmd('HDEL', [ this.key_usr_tpl({ owner:owner }), tpl_id ], (err, deleted) => { + if (err) { + return callback(err); } - ); + + if (!deleted) { + return callback(new Error(`Template '${tpl_id}' of user '${owner}' does not exist`)); + } + + this.emit('delete', owner, tpl_id); + return callback(); + }); }; // Update a template @@ -296,56 +298,58 @@ TemplateMaps.prototype.delTemplate = function(owner, tpl_id, callback) { // @param callback function(err) // TemplateMaps.prototype.updTemplate = function(owner, tpl_id, template, callback) { - - var self = this; - template = templateDefaults(template); var invalidError = this._checkInvalidTemplate(template); - - if ( invalidError ) { + if (invalidError) { return callback(invalidError); } - var templateName = template.name; - - if ( tpl_id !== templateName ) { - return callback(new Error("Cannot update name of a map template ('" + tpl_id + "' != '" + templateName + "')")); + if (tpl_id !== template.name) { + return callback(new Error(`Cannot update name of a map template ('${tpl_id}' != '${template.name}')`)); } - var userTemplatesKey = this.key_usr_tpl({ owner:owner }); + var userTemplatesKey = this.key_usr_tpl({ owner }); - var previousTemplate = null; + this._redisCmd('HGET', [userTemplatesKey, tpl_id], (err, beforeUpdateTemplate) => { + if (err) { + return callback(err); + } - step( - function getExistingTemplate() { - self._redisCmd('HGET', [ userTemplatesKey, tpl_id ], this); - }, - function updateTemplate(err, _currentTemplate) { - assert.ifError(err); - if (!_currentTemplate) { - throw new Error("Template '" + tpl_id + "' of user '" + owner + "' does not exist"); + if (!beforeUpdateTemplate) { + return callback(new Error(`Template '${tpl_id}' of user '${owner}' does not exist`)); + } + + let templateString; + try { + templateString = JSON.stringify(template); + } catch (error) { + return callback(error); + } + + this._redisCmd('HSET', [userTemplatesKey, template.name, templateString], (err, didSetNewField) => { + if (err) { + return callback(err); } - previousTemplate = _currentTemplate; - self._redisCmd('HSET', [ userTemplatesKey, templateName, JSON.stringify(template) ], this); - }, - function handleTemplateUpdate(err, didSetNewField) { - assert.ifError(err); + if (didSetNewField) { debug('New template created on update operation'); } - return true; - }, - function finish(err) { - if (!err) { - if (self.fingerPrint(JSON.parse(previousTemplate)) !== self.fingerPrint(template)) { - self.emit('update', owner, templateName, template); - } + + let beforeUpdateTemplateObject; + try { + beforeUpdateTemplateObject = JSON.parse(beforeUpdateTemplate); + } catch (error) { + return callback(error); } - callback(err, template); - } - ); + if (this.fingerPrint(beforeUpdateTemplateObject) !== this.fingerPrint(template)) { + this.emit('update', owner, template.name, template); + } + + return callback(null, template); + }); + }); }; // List user templates @@ -370,19 +374,20 @@ TemplateMaps.prototype.listTemplates = function(owner, callback) { // Return full template definition // TemplateMaps.prototype.getTemplate = function(owner, tpl_id, callback) { - var self = this; - step( - function getTemplate() { - self._redisCmd('HGET', [ self.key_usr_tpl({owner:owner}), tpl_id ], this); - }, - function parseTemplate(err, tpl_val) { - assert.ifError(err); - return JSON.parse(tpl_val); - }, - function finish(err, tpl) { - callback(err, tpl); + this._redisCmd('HGET', [this.key_usr_tpl({owner:owner}), tpl_id], (err, template) => { + if (err) { + return callback(err); } - ); + + let templateObject; + try { + templateObject = JSON.parse(template); + } catch (error) { + return callback(error); + } + + return callback(null, templateObject); + }); }; TemplateMaps.prototype.isAuthorized = function(template, authTokens) {