diff --git a/lib/handlers.js b/lib/handlers.js index 8f7f96b..371e522 100644 --- a/lib/handlers.js +++ b/lib/handlers.js @@ -1,4 +1,5 @@ module.exports = function (mongoDataInstance, previewInstance, importerInstance) { + "use strict"; function getAttribute(options, callback) { mongoDataInstance.getMongoAttribute(options, callback); @@ -21,5 +22,5 @@ module.exports = function (mongoDataInstance, previewInstance, importerInstance) getContent: getContent, getPreviewHTML: getPreviewHTML, importer: importer - } + }; }; diff --git a/lib/helpers.js b/lib/helpers.js index 1715270..51fe0bc 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -2,7 +2,7 @@ var when = require('when'); var _ = require('underscore'); module.exports = function (markers) { - + "use strict"; function replace(text, marker, getReplacement, once) { var deferred = when.defer(); var regExp = new RegExp(markers.prefix + marker + markers.postfix, 'gmi'); @@ -23,13 +23,11 @@ module.exports = function (markers) { regExp: replacement.regExp || regExp, replacement: replacement.value }; - deferred2.resolve(replace_result) + deferred2.resolve(replace_result); } - }) + }); }); - when.all( - match_promises - ).then( + when.all(match_promises).then( function onSuccess(results) { deferred.resolve(results); }, @@ -44,9 +42,7 @@ module.exports = function (markers) { } function handTextManipulation(text, promises, handler, callback) { - when.all( - promises - ).then( + when.all(promises).then( function onSuccess(all_results) { _.forEach(all_results, function loopResults(results) { _.forEach(results, function handleResult(result) { @@ -58,11 +54,11 @@ module.exports = function (markers) { function onFailure(err) { return callback(err); } - ) + ); } return { replace: replace, handTextManipulation: handTextManipulation - } + }; }; diff --git a/lib/importer.js b/lib/importer.js index 5b62c85..f71027b 100644 --- a/lib/importer.js +++ b/lib/importer.js @@ -5,70 +5,18 @@ var fs = require('fs'); module.exports = function (config, mongoInstance, helpers, markers) { + "use strict"; - var import_leftovers_tag = markers.import_leftovers_tag; - var import_leftovers_regexp = markers.import_leftovers_regexp; + var replaceMarkers; - var importer = function (doc, options, cb) { - when.any( - helpers.replace(doc, import_leftovers_tag, function getReplacement(result, callback) { - var parts = import_leftovers_regexp.exec(result); - var context = { - collection: parts[1], - name: parts[2], - attribute: parts[3] - }; - return callback(null, { - regExp: new RegExp(result, 'gmi'), - value: context - }); - }, - // there can be only one import_leftovers - true - ) - ).then( - function onSuccess(leftover) { - handleImportMarkers(doc, options, function handleLeftover(err, remainder) { - if (err) { - config.errors && console.log('ERR importer.importer handleImportMarkers', err); - return cb(err); - } - if (leftover) { - return mongoInstance.ensureContent(leftover.replacement, function parent(err, parent_result) { - if (err) { - config.errors && console.log('ERR importer.importer ensureContent', err); - return cb(err); - } - leftover.replacement.query = { _id: parent_result._id }; - - remainder = remainder.replace(leftover.regExp, ""); - return mongoInstance.setMongoAttribute(remainder, leftover.replacement, function savedAttribute(err) { - if (err) { - config.errors && console.log('ERR importer.importer setMongoAttribute', err); - return cb(err); - } - return cb(null, remainder); - }) - }) - } else { - config.debug && console.log('no import_leftover tag found'); - return cb(null, remainder); - } - }); - }, - function onFailure(err) { - config.errors && console.log('ERR importer.importer onFailure', err); - return cb(err); - } - ) - }; - - var handleImportMarkers = function (doc, options, callback) { + function handleImportMarkers(doc, options, callback) { var promises = replaceMarkers(doc, options); function handler(text, result) { var new_text = text.replace(result.regExp, result.replacement); - config.debug && console.log('handleImportMarker.handler new_text', new_text); + if (config.debug) { + console.log('handleImportMarker.handler new_text', new_text); + } return new_text; } @@ -77,7 +25,132 @@ module.exports = function (config, mongoInstance, helpers, markers) { handler, callback ); - }; + } + + var import_leftovers_tag = markers.import_leftovers_tag; + var import_leftovers_regexp = markers.import_leftovers_regexp; + + function importer(doc, options, cb) { + var promises = helpers.replace(doc, import_leftovers_tag, + function getReplacement(result, callback) { + var parts = import_leftovers_regexp.exec(result); + var context = { + collection: parts[1], + name: parts[2], + attribute: parts[3] + }; + return callback(null, { + regExp: new RegExp(result, 'gmi'), + value: context + }); + }, + // there can be only one import_leftovers + true + ); + when.any(promises).then( + function onSuccess(leftover) { + handleImportMarkers(doc, options, function handleLeftover(err, remainder) { + if (err) { + if (config.errors) { + console.error('ERR importer.importer handleImportMarkers', err); + } + return cb(err); + } + if (leftover) { + return mongoInstance.ensureContent(leftover.replacement, function parent(err, parent_result) { + if (err) { + if (config.errors) { + console.error('ERR importer.importer ensureContent', err); + } + return cb(err); + } + leftover.replacement.query = { _id: parent_result._id }; + + remainder = remainder.replace(leftover.regExp, ""); + return mongoInstance.setMongoAttribute(remainder, leftover.replacement, function savedAttribute(err) { + if (err) { + if (config.errors) { + console.error('ERR importer.importer setMongoAttribute', err); + } + return cb(err); + } + return cb(null, remainder); + }); + }); + } + if (config.debug) { + console.log('no import_leftover tag found'); + } + return cb(null, remainder); + }); + }, + function onFailure(err) { + if (config.errors) { + console.error('ERR importer.importer onFailure', err); + } + return cb(err); + } + ); + } + + + function importRemainder(context, result, remainder, callback) { + return mongoInstance.ensureContent(context, function parent(err, parent_result) { + if (err) { + if (config.errors) { + console.error('ERR importer.importer ensureContent', err); + } + return callback(err); + } + function replaceWithEmptyContent(err) { + var replacement = { + regExp: result, + value: "" + }; + return callback(err, replacement); + } + + if (context.attribute === "json") { + var data = null; + try { + data = JSON.parse(remainder); + } catch (error) { + if (config.errors) { + console.error('ERR importer.replaceMarkers JSON.parse(remainder)', remainder, error); + } + return callback(error); + } + if (data._id) { + delete data._id; + } + _.extend(parent_result, data); + context.update = true; + return mongoInstance.setMongoContent(parent_result, context, function (err) { + if (err) { + if (config.errors) { + console.error('ERR importer.importRemainder setMongoContent', err); + } + return callback(err); + } + var documentId = 'json:' + context.collection + ':' + context.name; + var keys = _.keys(parent_result); // reset all attributes; + return mongoInstance.updateShareDocument(documentId, parent_result, keys, function () { + return replaceWithEmptyContent(null); + }); + }); + } + context.query = { _id: parent_result._id }; + return mongoInstance.setMongoAttribute(remainder, context, function savedAttribute(err) { + if (err) { + if (config.errors) { + console.error('ERR2 importer.importer setMongoAttribute', err); + } + return callback(err); + } + return replaceWithEmptyContent(null); + }); + }); + } var import_tag = markers.import_tag; var import_regexp = markers.import_regexp; @@ -86,7 +159,7 @@ module.exports = function (config, mongoInstance, helpers, markers) { var import_file_tag = markers.import_file_tag; var import_file_regexp = markers.import_file_regexp; - var replaceMarkers = function (doc, options) { + replaceMarkers = function (doc, options) { var promises = []; promises.push( @@ -102,7 +175,9 @@ module.exports = function (config, mongoInstance, helpers, markers) { handleImportMarkers(sub_doc, options, function handleLeftover(err, remainder) { if (err) { - config.errors && console.log('ERR importer.replaceMarkers import_content_marker', err); + if (config.errors) { + console.error('ERR importer.replaceMarkers import_content_marker', err); + } return callback(err); } return importRemainder(context, result, remainder, callback); @@ -122,13 +197,17 @@ module.exports = function (config, mongoInstance, helpers, markers) { }; fs.readFile(filename, 'utf-8', function handleFileContent(err, sub_doc) { if (err) { - config.errors && console.log('ERR importer.replaceMarkers readFile', err); + if (config.errors) { + console.error('ERR importer.replaceMarkers readFile', err); + } return callback(err); } // process with leftover marker support return importer(sub_doc, context, function handleLeftover(err, remainder) { if (err) { - config.errors && console.log('ERR importer.replaceMarkers importer', err); + if (config.errors) { + console.error('ERR importer.replaceMarkers importer', err); + } return callback(err); } return importRemainder(context, result, remainder, callback); @@ -140,58 +219,8 @@ module.exports = function (config, mongoInstance, helpers, markers) { return promises; }; - function importRemainder( context, result, remainder, callback) { - return mongoInstance.ensureContent(context, function parent(err, parent_result) { - if (err) { - config.errors && console.log('ERR importer.importer ensureContent', err); - return callback(err); - } - function replaceWithEmptyContent(err) { - var replacement = { - regExp: result, - value: "" - }; - return callback(err, replacement); - } - - if (context.attribute == "json") { - var data = null; - try { - data = JSON.parse(remainder); - } catch (err) { - config.errors && console.log('ERR importer.replaceMarkers JSON.parse(remainder)', remainder, err); - return callback(err); - } - if (data._id) { - delete data._id; - } - _.extend(parent_result, data); - context.update = true; - return mongoInstance.setMongoContent(parent_result, context, function (err) { - if (err) { - config.errors && console.log('ERR importer.importRemainder setMongoContent', err); - return callback(err); - } - var documentId = 'json:' + context.collection + ':' + context.name; - var keys = _.keys(parent_result); // reset all attributes; - return mongoInstance.updateShareDocument(documentId, parent_result, keys, function () { - return replaceWithEmptyContent(null); - }); - }); - } else { - context.query = { _id: parent_result._id }; - return mongoInstance.setMongoAttribute(remainder, context, function savedAttribute(err) { - if (err) { - config.errors && console.log('ERR2 importer.importer setMongoAttribute', err); - return callback(err); - } - return replaceWithEmptyContent(null); - }); - } - }); - } return { importer: importer - } + }; }; diff --git a/lib/markers.js b/lib/markers.js index 846e40d..8418314 100644 --- a/lib/markers.js +++ b/lib/markers.js @@ -1,4 +1,6 @@ module.exports = function markers(config) { + "use strict"; + var marker_prefix = ''; @@ -34,7 +36,10 @@ module.exports = function markers(config) { function createTag(type, collection, name, attribute) { - return ''; + var tag = ''; + if(config.debug) { + console.log('markers.createTag created:', tag); + } } return { @@ -60,5 +65,5 @@ module.exports = function markers(config) { import_strip_regexp:import_strip_regexp, import_file_tag:import_file_tag, import_file_regexp:import_file_regexp - } + }; }; diff --git a/lib/mongodata.js b/lib/mongodata.js index bf6470a..e991f22 100644 --- a/lib/mongodata.js +++ b/lib/mongodata.js @@ -3,17 +3,21 @@ var _ = require('underscore'); module.exports = function (config, db, shareModel) { - + "use strict"; /* options: * collection (mandatory) * query (mandatory) */ function getMongoContent(options, callback) { - config.debug && console.log('getMongoContent options', options); + if (config.debug) { + console.log('getMongoContent options', options); + } return db.collection(options.collection, function collection(err, col) { if (err) { - config.errors && console.log('ERR2 getMongoContent', err); + if (config.errors) { + console.error('ERR2 getMongoContent', err); + } return callback(err); } if (!options.query) { @@ -22,14 +26,18 @@ module.exports = function (config, db, shareModel) { if (options.query._id && !(options.query._id instanceof Object)) { try { options.query._id = new ObjectID.createFromHexString(options.query._id); - } catch (err) { - config.errors && console.log('ERR3 getMongoContent', err); - return callback(err); + } catch (error) { + if (config.errors) { + console.error('ERR3 getMongoContent', error); + } + return callback(error); } } return col.findOne(options.query, function foundOne(err, result) { if (err) { - config.errors && console.log('ERR4 getMongoContent', err); + if (config.errors) { + console.error('ERR4 getMongoContent', err); + } return callback(err); } if (!result) { @@ -40,13 +48,301 @@ module.exports = function (config, db, shareModel) { }); } + + /* + options: + * collection (mandatory) + * query (mandatory) + * attribute (mandatory) + */ + function getMongoAttribute(options, callback) { + if (config.debug) { + console.log('getMongoAttribute options', options); + } + return getMongoContent(options, function document(err, result) { + if (err) { + if (config.errors) { + console.error('ERR1 getMongoAttribute', err); + } + return callback(err); + } + var attribute_options = null; + if (config.debug) { + console.log('getMongoAttribute result', result); + } + if (result && + result.hasOwnProperty(options.attribute) && + result[options.attribute].guid) { + attribute_options = { + collection: options.collection, + query: {_id: result[options.attribute].guid} + }; + if (config.debug) { + console.log('getMongoAttribute attribute_options', attribute_options); + } + + getMongoContent(attribute_options, function attribute(err, attribute_result) { + if (err) { + if (config.errors) { + console.error('ERR2 getMongoAttribute', err); + } + return callback(err); + } + if (config.debug) { + console.log('getMongoAttribute attribute_result', attribute_result); + } + return callback(err, attribute_result); + }); + } else { + if (config.debug) { + console.log('getMongoAttribute try direct lookup'); + } + attribute_options = { + collection: options.collection, + query: { + parent: result._id, + name: result.name + '.' + options.attribute + } + }; + if (config.debug) { + console.log('getMongoAttribute attribute_options', attribute_options); + } + + return getMongoContent(attribute_options, function attribute(err, attribute_result) { + if (err) { + if (config.errors) { + console.error('ERR getMongoAttribute', err); + } + return callback(err); + } + if (config.debug) { + console.log('getMongoAttribute direct attribute_result', attribute_result); + } + return callback(err, attribute_result); + }); + } + }); + } + + function saveData(collection, data, callback) { + if (data._id && !(data._id instanceof Object)) { + data._id = new ObjectID.createFromHexString(data._id); + } + if (config.debug) { + console.log('saveData saving', data._id); + } + collection.save(data, {safe: true}, function (err, result2, result3) { + if (err) { + if (config.errors) { + console.error('ERR saveData', err); + } + return callback(err); + + } + if (config.debug) { + console.log('saveData saved', data._id, result2, result3); + } + return callback(null, data, collection); + }); + } + + var updating = false; + + function updateData(collection, data, callback) { + if (updating) { + //noinspection JSUnresolvedFunction + setImmediate(function rescheduling() { + if (config.debug) { + console.log('Updating, rescheduling'); + } + return updateData(collection, data, callback); + }); + } else { + updating = true; + var stopUpdating = function (err, result, col) { + if (config.debug) { + console.log('Stop updating'); + } + updating = false; + if (err) { + return callback(err); + } + return callback(null, result, col); + }; + + return collection.findOne({ _id: data._id}, function foundOne(err, result) { + if (err) { + if (config.errors) { + console.error('ERR updateData', err); + } + return callback(err); + } + _.extend(result, data); + return saveData(collection, result, stopUpdating); + }); + } + } + + + /* + options: + * collection (mandatory) + * query (mandatory) + * update (optional) : extends existing content + */ + function setMongoContent(data, options, callback) { + if (config.debug) { + console.log('setMongoContent options', options); + } + return db.collection(options.collection, function handleCollection(err, collection) { + if (err) { + if (config.errors) { + console.error('ERR2 setMongoContent', err); + } + return callback(err); + } + if (options.operation) { + data.version = options.operation.v; + } + var dumpData = saveData; + if (options.update) { + dumpData = updateData; + } + if (!data._id) { + if (config.debug) { + console.log('setMongoContent lookup by query', options.query, 'updating:', options.update); + } + collection.findOne(options.query, function foundOne(err, result) { + if (err) { + if (config.errors) { + console.error('ERR3 setMongoContent', err); + } + return callback(err); + } + if (result) { + data._id = result._id; + } + return dumpData(collection, data, callback); + }); + } else { + return dumpData(collection, data, callback); + } + }); + } + + function updateShareDocumentPath(documentId, data, path, callback) { + shareModel.getSnapshot(documentId, function (err, doc) { + if (err) { + if (config.errors) { + console.error('WARN setMongoAttribute updateShareDocumentPath shareModel.getSnapshot', documentId, err); + } + return callback && callback(); + } + var sub_data = data; + var sub_snapshot_data = doc.snapshot; + var equal_path = []; + var found = false; + var x; + for (x = 0; !found && x < path.length; x += 1) { + var key = path[x]; + if (sub_data && sub_data.hasOwnProperty(key) + && sub_snapshot_data && sub_snapshot_data.hasOwnProperty(key)) { + sub_data = sub_data[key]; + sub_snapshot_data = sub_snapshot_data[key]; + equal_path.push(key); + } else if (!sub_snapshot_data || !sub_snapshot_data.hasOwnProperty(key)) { + found = true; + } + } + if (found) { + path = equal_path; + } + var op = { + p: path + }; + if (sub_data) { + op.oi = sub_data; + } + if (sub_snapshot_data) { + op.od = sub_snapshot_data; + } + return shareModel.applyOp(documentId, { op: [op], v: doc.v }, function (err, result) { + if (err) { + if (config.errors) { + console.error('ERR updateShareDocumentPath shareModel.applyOp', documentId, err); + } + return callback && callback(); + } + if (config.debug) { + console.log('updateShareDocumentPath shareModel.applyOp', documentId, op, err, result); + } + return callback && callback(); + + }); + }); + } + + function updateShareDocument(documentId, data, keys, callback) { + if (!keys) { + // no keys no update + return callback && callback(); + } + var ops = []; + return shareModel.getSnapshot(documentId, function (err, doc) { + if (err) { + if (config.errors) { + console.error('WARN updateShareDocument shareModel.getSnapshot', documentId, err); + } + return callback && callback(); + } + if (doc.type.name === 'text') { + ops.push({ + d: doc.snapshot, p: 0 + }); + ops.push({ + i: data, p: 0 + }); + } else if (doc.type.name === 'json') { + _.forEach(keys, function (key) { + if (key !== '_id') { + var op = { + p: [key] + }; + if (doc.snapshot[key]) { + op.od = doc.snapshot[key]; + } + if (data[key]) { + op.oi = data[key]; + } + ops.push(op); + } + }); + } + return shareModel.applyOp(documentId, { op: ops, v: doc.v }, function (err, result) { + if (err) { + if (config.errors) { + console.error('WARN updateShareDocument shareModel.applyOp', documentId, err); + } + return callback && callback(); + } + if (config.debug) { + console.log('updateShareDocument shareModel.applyOp', documentId, ops, err, result); + } + return callback && callback(); + }); + }); + } + + var ensuring = false; function ensureContent(options, callback) { if (ensuring) { //noinspection JSUnresolvedFunction setImmediate(function rescheduling() { - config.debug && console.log('Ensuring, rescheduling', options); + if (config.debug) { + console.log('Ensuring, rescheduling', options); + } return ensureContent(options, callback); }); } else { @@ -54,23 +350,25 @@ module.exports = function (config, db, shareModel) { if (!options.query) { options.query = { name: options.name - } + }; } - function stopEnsuring(err, result, col) { - config.debug && console.log('Stop ensuring', options); + var stopEnsuring = function (err, result, col) { + if (config.debug) { + console.log('Stop ensuring', options); + } ensuring = false; if (err) { return callback(err); } return callback(null, result, col); - } + }; getMongoContent(options, function document(err, result, col) { if (err) { if (/Data not found*/.test(err.message)) { var documentId = 'json:' + options.collection + ':' + options.name; var data = {name: options.name}; - return setMongoContent(data, options, function (err, content_result, col) { + setMongoContent(data, options, function (err, content_result, col) { var keys = _.keys(data); // reset all attributes; return updateShareDocument(documentId, data, keys, function updatedShareDocument() { stopEnsuring(err, content_result, col); @@ -86,155 +384,19 @@ module.exports = function (config, db, shareModel) { } } - /* - options: - * collection (mandatory) - * query (mandatory) - * attribute (mandatory) - */ - function getMongoAttribute(options, callback) { - config.debug && console.log('getMongoAttribute options', options); - return getMongoContent(options, function document(err, result) { - if (err) { - config.errors && console.log('ERR1 getMongoAttribute', err); - return callback(err); - } - var attribute_options = null; - config.debug && console.log('getMongoAttribute result', result); - if (result - && result.hasOwnProperty(options.attribute) - && result[options.attribute].guid) { - attribute_options = { - collection: options.collection, - query: {_id: result[options.attribute].guid} - }; - config.debug && console.log('getMongoAttribute attribute_options', attribute_options); - - return getMongoContent(attribute_options, function attribute(err, attribute_result) { - if (err) { - config.errors && console.log('ERR2 getMongoAttribute', err); - return callback(err); - } - config.debug && console.log('getMongoAttribute attribute_result', attribute_result); - return callback(err, attribute_result); - }); - } else { - config.debug && console.log('getMongoAttribute try direct lookup'); - attribute_options = { - collection: options.collection, - query: { - parent: result._id, - name: result.name + '.' + options.attribute - } - }; - config.debug && console.log('getMongoAttribute attribute_options', attribute_options); - - return getMongoContent(attribute_options, function attribute(err, attribute_result) { - if (err) { - config.errors && console.log('ERR getMongoAttribute', err); - return callback(err); - } - config.debug && console.log('getMongoAttribute direct attribute_result', attribute_result); - return callback(err, attribute_result); - }); - } - }) - } - - - var updating = false; - - function updateData(collection, data, callback) { - if (updating) { - //noinspection JSUnresolvedFunction - return setImmediate(function rescheduling() { - config.debug && console.log('Updating, rescheduling'); - return updateData(collection, data, callback); - }); - } else { - updating = true; - function stopUpdating(err, result, col) { - config.debug && console.log('Stop updating'); - updating = false; - if (err) { - return callback(err); - } - return callback(null, result, col); - } - - return collection.findOne({ _id: data._id}, function foundOne(err, result) { - if (err) { - config.errors && console.log('ERR updateData', err); - return callback(err); - } - _.extend(result, data); - return saveData(collection, result, stopUpdating); - }); - } - } - - function saveData(collection, data, callback) { - if (data._id && !(data._id instanceof Object)) { - data._id = new ObjectID.createFromHexString(data._id); - } - config.debug && console.log('saveData saving', data._id); - collection.save(data, {safe: true}, function (err, result2, result3) { - if (err) { - config.errors && console.log('ERR saveData', err); - return callback(err); - - } - config.debug && console.log('saveData saved', data._id, result2, result3); - return callback(null, data, collection); - }); - } - - /* - options: - * collection (mandatory) - * query (mandatory) - * update (optional) : extends existing content - */ - function setMongoContent(data, options, callback) { - config.debug && console.log('setMongoContent options', options); - return db.collection(options.collection, function collection(err, collection) { - if (err) { - config.errors && console.log('ERR2 setMongoContent', err); - return callback(err); - } - if (options.operation) { - data.version = options.operation.v; - } - var dumpData = saveData; - if (options.update) { - dumpData = updateData; - } - if (!data._id) { - config.debug && console.log('setMongoContent lookup by query', options.query, 'updating:', options.update); - return collection.findOne(options.query, function foundOne(err, result) { - if (err) { - config.errors && console.log('ERR3 setMongoContent', err); - return callback(err); - } - if (result) { - data._id = result._id; - } - return dumpData(collection, data, callback); - }) - } else { - return dumpData(collection, data, callback); - } - }); - } /* options: * no_share (optional): prevent share to update itself. */ function setMongoAttribute(data, options, callback) { - config.debug && console.log('setMongoAttribute options', options); + if (config.debug) { + console.log('setMongoAttribute options', options); + } ensureContent(options, function document(err, result, col) { if (err) { - config.errors && console.log('ERR1 setMongoAttribute', err); + if (config.errors) { + console.error('ERR1 setMongoAttribute', err); + } return callback(err); } var attribute_options = { @@ -250,19 +412,23 @@ module.exports = function (config, db, shareModel) { attribute_options.query = { parent: result._id, name: result.name + '.' + options.attribute - } + }; } - config.debug && console.log('getMongoAttribute parent found, get child and save', result, attribute_options); + if (config.debug) { + console.log('getMongoAttribute parent found, get child and save', result, attribute_options); + } return ensureContent(attribute_options, function attribute(err, attribute_result) { if (err) { - config.errors && console.log('ERR2 setMongoAttribute ensureContent', err); + if (config.errors) { + console.error('ERR2 setMongoAttribute ensureContent', err); + } return callback(err); } var updateContent = true; if (result[options.attribute]) { - if (attribute_result._id.toString() == String(result[options.attribute].guid)) { + if (attribute_result._id.toString() === String(result[options.attribute].guid)) { updateContent = false; } else { result[options.attribute].guid = attribute_result._id; @@ -279,7 +445,9 @@ module.exports = function (config, db, shareModel) { } return saveData(col, attribute_result, function saved(err) { if (err) { - config.errors && console.log('ERR3 setMongoAttribute', err); + if (config.errors) { + console.error('ERR3 setMongoAttribute', err); + } return callback(err); } var documentId = 'json:' + options.collection + ':' + result.name; @@ -287,7 +455,7 @@ module.exports = function (config, db, shareModel) { var attributeDocumentId = type + ':' + options.collection + ':' + result.name + ':' + options.attribute; var keys = null; var share_data = null; - if (type == 'json') { + if (type === 'json') { keys = _.keys(attribute_result); // reset all attributes; share_data = attribute_result; } else { @@ -299,9 +467,11 @@ module.exports = function (config, db, shareModel) { } return updateShareDocument(attributeDocumentId, share_data, keys, function updatedShareAttribute() { if (updateContent) { - return updateData(col, result, function saved(err) { + updateData(col, result, function saved(err) { if (err) { - config.errors && console.log('ERR3 setMongoAttribute', err); + if (config.errors) { + console.error('ERR3 setMongoAttribute', err); + } return callback(err); } var path = [options.attribute, 'guid']; // reset just guid attribute; @@ -310,7 +480,7 @@ module.exports = function (config, db, shareModel) { }); }); } else { - return callback(null, attribute_result, col); + callback(null, attribute_result, col); } }); }); @@ -318,98 +488,6 @@ module.exports = function (config, db, shareModel) { }); } - function updateShareDocument(documentId, data, keys, callback) { - if (!keys) { - // no keys no update - return callback && callback(); - } - var ops = []; - return shareModel.getSnapshot(documentId, function (err, doc) { - if (err) { - config.errors && console.log('WARN updateShareDocument shareModel.getSnapshot', documentId, err); - return callback && callback(); - } else { - if (doc.type.name == 'text') { - ops.push({ - d: doc.snapshot, p: 0 - }); - ops.push({ - i: data, p: 0 - }); - } else if (doc.type.name == 'json') { - _.forEach(keys, function (key) { - if (key != '_id') { - var op = { - p: [key] - }; - if (doc.snapshot[key]) { - op.od = doc.snapshot[key]; - } - if (data[key]) { - op.oi = data[key]; - } - ops.push(op); - } - }); - } - return shareModel.applyOp(documentId, { op: ops, v: doc.v }, function (err, result) { - if (err) { - config.errors && console.log('WARN updateShareDocument shareModel.applyOp', documentId, err); - return callback && callback(); - } - config.debug && console.log('updateShareDocument shareModel.applyOp', documentId, ops, err, result); - return callback && callback(); - }); - } - }); - } - - function updateShareDocumentPath(documentId, data, path, callback) { - shareModel.getSnapshot(documentId, function (err, doc) { - if (err) { - config.errors && console.log('WARN setMongoAttribute updateShareDocumentPath shareModel.getSnapshot', documentId, err); - return callback && callback(); - } else { - var sub_data = data; - var sub_snapshot_data = doc.snapshot; - var equal_path = []; - var found = false; - for (var x = 0; !found && x < path.length; x++) { - var key = path[x]; - if (sub_data && sub_data.hasOwnProperty(key) && - sub_snapshot_data && sub_snapshot_data.hasOwnProperty(key)) { - sub_data = sub_data[key]; - sub_snapshot_data = sub_snapshot_data[key]; - equal_path.push(key); - } else if (!sub_snapshot_data || !sub_snapshot_data.hasOwnProperty(key)) { - found = true; - } - } - if (found) { - path = equal_path; - } - var op = { - p: path - }; - if (sub_data) { - op.oi = sub_data; - } - if (sub_snapshot_data) { - op.od = sub_snapshot_data; - } - return shareModel.applyOp(documentId, { op: [op], v: doc.v }, function (err, result) { - if (err) { - config.errors && console.log('ERR updateShareDocumentPath shareModel.applyOp', documentId, err); - return callback && callback(); - } - config.debug && console.log('updateShareDocumentPath shareModel.applyOp', documentId, op, err, result); - return callback && callback(); - - }); - } - }); - } - return { getMongoAttribute: getMongoAttribute, getMongoContent: getMongoContent, diff --git a/lib/preview.js b/lib/preview.js index 730437f..18e1582 100644 --- a/lib/preview.js +++ b/lib/preview.js @@ -5,21 +5,8 @@ var less = require('less'); var when = require('when'); module.exports = function (config, mongoDataInstance, helpers, markers) { - - var getPreviewHTML = function (content, options, callback) { - config.debug && console.log('getPreviewHTML', content); - var promises = replaceMarkers(content, options); - - function handler(text, result) { - return text.replace(result.regExp, result.replacement); - } - - helpers.handTextManipulation(content, - promises, - handler, - callback - ); - }; + "use strict"; + var getPreviewHTML; var script_tag = markers.script_tag; var script_regexp = markers.script_regexp; @@ -106,12 +93,16 @@ module.exports = function (config, mongoDataInstance, helpers, markers) { }; return mongoDataInstance.getMongoContent(context, function handleContext(err, context_result) { if (err) { - config.errors && console.log('ERR template_tag getMongoContent', context); + if (config.errors) { + console.error('ERR template_tag getMongoContent', context); + } return callback(err); } return mongoDataInstance.getMongoAttribute(template, function handleTemplate(err, template_result) { if (err) { - config.errors && console.log('ERR template_tag getMongoAttribute', template, err); + if (config.errors) { + console.error('ERR template_tag getMongoAttribute', template, err); + } return callback(err); } var compiled_template = null; @@ -121,11 +112,10 @@ module.exports = function (config, mongoDataInstance, helpers, markers) { return function () { if (keys_to_collect.hasOwnProperty(key)) { return keys_to_collect[key]; - } else { - keys_to_collect[key] = null; - return "waiting for content"; } - } + keys_to_collect[key] = null; + return "waiting for content"; + }; } // Handlebars is synchronous ouch !! @@ -140,9 +130,11 @@ module.exports = function (config, mongoDataInstance, helpers, markers) { }); try { compiled_template = handlebars.compile(template_result[template.attribute]); - } catch (err) { - config.errors && console.log('ERR template_tag Handlebars.compile', template, err); - return callback(err); + } catch (error1) { + if (config.errors) { + console.error('ERR template_tag Handlebars.compile', template, error1); + } + return callback(error1); } var extendHandlebars_context = function (result) { var handlebars = {}; @@ -158,9 +150,11 @@ module.exports = function (config, mongoDataInstance, helpers, markers) { var handlebars_context = extendHandlebars_context(context_result); try { compiled_template(handlebars_context); - } catch (err) { - config.errors && console.log('ERR template_tag Handlebars.render', template, context, err); - return callback(err); + } catch (error2) { + if (config.errors) { + console.error('ERR template_tag Handlebars.render', template, context, error2); + } + return callback(error2); } var promises = []; _.forEach(_.keys(keys_to_collect), function gatherKeyValues(key) { @@ -174,7 +168,9 @@ module.exports = function (config, mongoDataInstance, helpers, markers) { }; return mongoDataInstance.getMongoAttribute(attribute_context, function cacheTemplateKey(err, template_key_result) { if (err) { - config.errors && console.log('ERR handlebar.registerHelper getMongoAttribute', err); + if (config.errors) { + console.error('ERR handlebar.registerHelper getMongoAttribute', err); + } deferred.reject(err); } var value = template_key_result[key]; @@ -182,22 +178,26 @@ module.exports = function (config, mongoDataInstance, helpers, markers) { deferred.resolve(value); }); }); - return when.all( - promises - ).then( + return when.all(promises).then( function onSuccess() { var rendered = null; try { rendered = compiled_template(handlebars_context); } catch (err) { - config.errors && console.log('ERR template_tag Handlebars.render', template, context, err); + if (config.errors) { + console.error('ERR template_tag Handlebars.render', template, context, err); + } return callback(err); } - config.debug && console.log('// handle markers on rendered template'); + if (config.debug) { + console.log('// handle markers on rendered template'); + } context.query = {_id: context_result._id}; return getPreviewHTML(rendered, context, function handlePreviewResult(err, preview_html) { if (err) { - config.errors && console.log('ERR template_tag getPreviewHTML', err); + if (config.errors) { + console.error('ERR template_tag getPreviewHTML', err); + } return callback(err); } return callback(null, { @@ -207,10 +207,12 @@ module.exports = function (config, mongoDataInstance, helpers, markers) { }); }, function onFailure(err) { - config.errors && console.log('ERR template_tag resolving promises', err); + if (config.errors) { + console.error('ERR template_tag resolving promises', err); + } return callback(err); } - ) + ); }); }); })); @@ -249,6 +251,22 @@ module.exports = function (config, mongoDataInstance, helpers, markers) { return promises; }; + getPreviewHTML = function (content, options, callback) { + if (config.debug) { + console.log('getPreviewHTML', content); + } + var promises = replaceMarkers(content, options); + + function handler(text, result) { + return text.replace(result.regExp, result.replacement); + } + + helpers.handTextManipulation(content, + promises, + handler, + callback + ); + }; return { getPreviewHTML: getPreviewHTML, diff --git a/lib/routes.js b/lib/routes.js index f4f59b6..195cf28 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -4,12 +4,14 @@ var path = require('path'); var fs = require('fs'); module.exports = function (app, handlers, markers, config) { - + "use strict"; var route; route = config.api.data + '/:collection/:guid/:attribute.:ext(css|less|js|html)'; app.get(route, function getAttributeByGUID(req, res, next) { - config.debug && console.log('/data/:collection/:guid/:attribute.:ext(less|js|html)'); + if (config.debug) { + console.log('/data/:collection/:guid/:attribute.:ext(less|js|html)'); + } var options = { collection: req.params.collection, attribute: req.params.attribute, @@ -25,7 +27,9 @@ module.exports = function (app, handlers, markers, config) { route = config.api.data + '/:collection/:guid.:ext(json)'; app.get(route, function getContentByGUID(req, res, next) { - config.debug && console.log('/data/:collection/:guid.:ext(json)'); + if (config.debug) { + console.log('/data/:collection/:guid.:ext(json)'); + } var options = { collection: req.params.collection, ext: req.params.ext, @@ -40,7 +44,9 @@ module.exports = function (app, handlers, markers, config) { route = config.api.content + '/:collection/:name/:attribute.:ext(css|less|js|html)'; app.get(route, function getAttributeByName(req, res, next) { - config.debug && console.log('/content/:collection/:name/:attribute.:ext(less|js|html)'); + if (config.debug) { + console.log('/content/:collection/:name/:attribute.:ext(less|js|html)'); + } var options = { collection: req.params.collection, attribute: req.params.attribute, @@ -56,7 +62,9 @@ module.exports = function (app, handlers, markers, config) { route = config.api.content + '/content/:collection/:name.:ext(json)'; app.get(route, function getContentByName(req, res, next) { - config.debug && console.log('/content/:collection/:name.:ext(json)'); + if (config.debug) { + console.log('/content/:collection/:name.:ext(json)'); + } var options = { collection: req.params.collection, ext: req.params.ext, @@ -72,7 +80,9 @@ module.exports = function (app, handlers, markers, config) { route = config.api.preview + '/:collection/:name.:ext(html|md)'; app.get(route, function getPreviewContent(req, res, next) { - config.debug && console.log('/page/:collection/:name.:ext(html|md)'); + if (config.debug) { + console.log('/page/:collection/:name.:ext(html|md)'); + } var options = { collection: req.params.collection, ext: req.params.ext, @@ -81,9 +91,9 @@ module.exports = function (app, handlers, markers, config) { headers: req.headers } }; - if (options.ext == 'md') { + if (options.ext === 'md') { var attribute_parts = options.query.name.split('.'); - var markdownDocument = markers.createTag('markdown',options.collection, attribute_parts[0], attribute_parts[1]); + var markdownDocument = markers.createTag('markdown', options.collection, attribute_parts[0], attribute_parts[1]); return handlers.getPreviewHTML(markdownDocument, { req: options.req }, responder(options, res, next) ); @@ -106,8 +116,10 @@ module.exports = function (app, handlers, markers, config) { req: options.req }; - config.debug && console.log('getPreviewContent content', attribute_value); - return handlers.getPreviewHTML(attribute_value, preview_options, + if (config.debug) { + console.log('getPreviewContent content', attribute_value); + } + handlers.getPreviewHTML(attribute_value, preview_options, responder(options, res, next) ); } else { @@ -124,10 +136,14 @@ module.exports = function (app, handlers, markers, config) { route = config.api.importer + '/:filename'; app.get(route, function importFile(req, res, next) { var filename = path.resolve(config.statics.importer_path, req.params.filename); - config.debug && console.log('/importer/:filename', filename); + if (config.debug) { + console.log('/importer/:filename', filename); + } fs.readFile(filename, 'utf-8', function handleFileContent(err, sub_doc) { if (err) { - config.errors && console.log('ERR readFile', filename, err); + if (config.errors) { + console.error('ERR readFile', filename, err); + } next(err); } // process with leftover marker support diff --git a/lib/share.js b/lib/share.js index 0338400..32be6ae 100644 --- a/lib/share.js +++ b/lib/share.js @@ -1,11 +1,12 @@ var ShareJS = require('share'); module.exports = function (config, app, db) { + "use strict"; // share wraps express app with http.Server if (config && config.share && config.share.db - && config.share.db.type == 'mongo') { + && config.share.db.type === 'mongo') { config.share.db.client = db; } var server = ShareJS.server.attach(app, config.share); diff --git a/lib/shareHandlers.js b/lib/shareHandlers.js index 0be530b..2184b0f 100644 --- a/lib/shareHandlers.js +++ b/lib/shareHandlers.js @@ -1,4 +1,5 @@ module.exports = function (config, model, mongoDataInstance) { + "use strict"; var timers = {}; function handleMongoGetResult(options) { @@ -6,10 +7,12 @@ module.exports = function (config, model, mongoDataInstance) { var notFound = false; if (err) { if (/Data not found*/.test(err.message)) { - config.debug && console.log('handleMongoGetResult.handleResult Document/Attribute not found, It will be created on first OT'); + if (config.debug) { + console.log('handleMongoGetResult.handleResult Document/Attribute not found, It will be created on first OT'); + } result = {}; if (options.attribute) { - if (options.type == 'json') { + if (options.type === 'json') { result[options.attribute] = {}; } else { result[options.attribute] = ""; @@ -17,34 +20,42 @@ module.exports = function (config, model, mongoDataInstance) { } notFound = true; } else { - config.errors && console.log('ERR1 handleMongoGetResult.handleResult Error retrieving document ', options.collection, JSON.stringify(options.query), options.attribute || "", err); + if (config.errors) { + console.error('ERR1 handleMongoGetResult.handleResult Error retrieving document ', options.collection, JSON.stringify(options.query), options.attribute || "", err); + } } } if (result || notFound) { var operation = null; - config.debug && console.log('handleMongoGetResult options', options, result); + if (config.debug) { + console.log('handleMongoGetResult options', options, result); + } var data = result; if (options.attribute) { data = result[options.attribute]; } var version = 0; - if (options.type == 'json') { + if (options.type === 'json') { if (data instanceof String) { data = JSON.parse(data); } operation = { op: [ { p: [], oi: data, od: null } ], v: version }; - } else if (options.type == 'text') { + } else if (options.type === 'text') { operation = { op: [ {i: data, p: 0} ], v: version }; } if (operation) { model.applyOp(options.documentId, operation, function appliedOp(error, version) { - options.debug && console.log('getResult applyOp version', version); + if (config.debug) { + console.log('getResult applyOp version', version); + } if (error) { - options.error && console.log('ERR2 handleMongoGetResult', error); + if (config.error) { + console.error('ERR2 handleMongoGetResult', error); + } } }); } @@ -55,7 +66,9 @@ module.exports = function (config, model, mongoDataInstance) { } model.on('create', function populateDocument(documentId, data) { - config.debug && console.log('Populating a doc in channel', documentId, data); + if (config.debug) { + console.log('Populating a doc in channel', documentId, data); + } var splitId = documentId.split(':'); var options = { documentId: documentId, @@ -63,7 +76,7 @@ module.exports = function (config, model, mongoDataInstance) { collection: splitId[1], attribute: null }; - if (splitId.length == 4) { + if (splitId.length === 4) { // options.query = {_id: splitId[2]}; options.query = {name: splitId[2]}; options.attribute = splitId[3]; @@ -78,19 +91,27 @@ module.exports = function (config, model, mongoDataInstance) { function handleMongoSetResult(options, current, callback) { function handleResult(err, result) { if (err) { - config.errors && console.log('ERR1 handleMongoSetResult Error while saving document ', options.collection, JSON.stringify(options.query), options.attribute || "", err); + if (config.errors) { + console.error('ERR1 handleMongoSetResult Error while saving document ', options.collection, JSON.stringify(options.query), options.attribute || "", err); + } return callback && callback(err); } - config.debug && console.log('current', current, 'result', result, 'options', options); + if (config.debug) { + console.log('current', current, 'result', result, 'options', options); + } if ((!current || !current.name) && (result.name || options.name)) { var name = result.name || options.name; var operation = { op: [ { p: ['name'], oi: name, od: null } ], v: options.operation.v }; - return model.applyOp(options.documentId, operation, function appliedOp(error, version) { - config.debug && console.log('setResult applyOp version', version); + model.applyOp(options.documentId, operation, function appliedOp(error, version) { + if (config.debug) { + console.log('setResult applyOp version', version); + } if (error) { - config.error && console.log('ERR2 handleMongoSetResult', error); + if (config.error) { + console.error('ERR2 handleMongoSetResult', error); + } return callback && callback(error); } return callback && callback(null, version); @@ -106,10 +127,14 @@ module.exports = function (config, model, mongoDataInstance) { function handleMongoAttributeSetResult(options, current, callback) { function handleResult(err, result) { if (err) { - config.errors && console.log('ERR1 handleMongoAttributeSetResult Error while saving document ', options.collection, JSON.stringify(options.query), options.attribute || "", err); + if (config.errors) { + console.error('ERR1 handleMongoAttributeSetResult Error while saving document ', options.collection, JSON.stringify(options.query), options.attribute || "", err); + } return callback(err); } - config.debug && console.log('current', current, 'result', result); + if (config.debug) { + console.log('current', current, 'result', result); + } return callback(null, null); } @@ -121,12 +146,16 @@ module.exports = function (config, model, mongoDataInstance) { return function saveContent() { var args = timers[documentId]; delete timers[documentId]; - config.debug && console.log('running timer', documentId); + if (config.debug) { + console.log('running timer', documentId); + } mongoDataInstance.setMongoContent(args.current, args.options, handleMongoSetResult(args.options, args.current, function handleApplyOpResult(err, version) { if (err) { - config.errors && console.log('ERR2 applyOp', version, err); + if (config.errors) { + console.error('ERR2 applyOp', version, err); + } } })); }; @@ -136,16 +165,20 @@ module.exports = function (config, model, mongoDataInstance) { return function saveAttribute() { var args = timers[documentId]; delete timers[documentId]; - config.debug && console.log('running timer', documentId); + if (config.debug) { + console.log('running timer', documentId); + } var data = args.current; - if (args.options.type == 'json') { + if (args.options.type === 'json') { data = JSON.parse(args.current); } mongoDataInstance.setMongoAttribute(data, args.options, handleMongoAttributeSetResult(args.options, data, function handleApplyOpResult(err, version) { if (err) { - config.errors && console.log('ERR1 applyOp', documentId, version, err); + if (config.errors) { + console.error('ERR1 applyOp', documentId, version, err); + } } })); }; @@ -154,8 +187,12 @@ module.exports = function (config, model, mongoDataInstance) { // 'applyOp' event is fired when an operational transform is applied to to a shareDoc // a shareDoc has changed and needs to be saved to mongo model.on('applyOp', function persistDocument(documentId, operation, current) { - config.debug && console.log('applyOp', documentId, operation, current); - if (operation.v == 0) return; + if (config.debug) { + console.log('applyOp', documentId, operation, current); + } + if (operation.v === 0) { + return; + } var splitId = documentId.split(':'); var options = { @@ -172,7 +209,7 @@ module.exports = function (config, model, mongoDataInstance) { options: options }; var attribute = false; - if (splitId.length == 4) { + if (splitId.length === 4) { // options.query = {_id: splitId[2]}; options.query = {name: splitId[2]}; options.attribute = splitId[3]; @@ -183,7 +220,9 @@ module.exports = function (config, model, mongoDataInstance) { if (timers[documentId]) { timer.timer_id = timers[documentId].timer_id; timers[documentId] = timer; - config.debug && console.log('resetting timer', documentId); + if (config.debug) { + console.log('resetting timer', documentId); + } } else { timers[documentId] = timer; if (attribute) { @@ -195,7 +234,9 @@ module.exports = function (config, model, mongoDataInstance) { handleSetTimeout(documentId), config.savedelay); } - config.debug && console.log('setting timer', documentId); + if (config.debug) { + console.log('setting timer', documentId); + } } }); }; diff --git a/server.js b/server.js index a230416..6b1175a 100644 --- a/server.js +++ b/server.js @@ -15,7 +15,7 @@ var markers = require('./lib/markers.js'); var helpers = require('./lib/helpers.js'); mime.define({ - 'text/css': ['css','less'] + 'text/css': ['css', 'less'] }); var config = { @@ -64,21 +64,27 @@ var config = { } }; -config.debug && console.log('config loaded'); +if (config.debug) { + console.log('config loaded'); +} var app = express(); -config.debug && app.use(connect.logger()); +if (config.debug) { + app.use(connect.logger()); +} +//noinspection JSUnresolvedFunction app.use(express.compress()); if (!process.env.NODE_ENV) { app.get('/favicon.ico', function (req, res) { - res.sendfile(config.statics.dev_favicon_path); + "use strict"; + res.sendfile(config.statics.dev_favicon_path, null, null); }); } //noinspection JSUnresolvedFunction app.use(express.static(config.statics.public_path)); //noinspection JSUnresolvedFunction -app.use('/doc',express.static(config.statics.doc_path)); +app.use('/doc', express.static(config.statics.doc_path)); //noinspection JSUnresolvedFunction app.use('/lib/markdown', express.static(config.statics.markdown_client)); //noinspection JSUnresolvedFunction @@ -86,50 +92,73 @@ app.use('/lib/ace', express.static(config.statics.ace_client)); //noinspection JSUnresolvedFunction app.use('/lib/async', express.static(config.statics.async_client)); -config.debug && console.log('static routes set'); +if (config.debug) { + console.log('static routes set'); +} var markerInstance = markers(config); var helperInstance = helpers(markerInstance); MongoClient.connect(config.mongo.server, config.mongo.options, function connection(err, db) { + "use strict"; if (err) { - config.errors && console.log('ERR connection to database', err); + if (config.errors) { + console.error('ERR connection to database', err); + } return process.exit(1); } - config.debug && console.log('database connected'); + if (config.debug) { + console.log('database connected'); + } var share = shareServer(config, app, db); var model = share.model; var server = share.server; - config.debug && console.log('share attached'); + if (config.debug) { + console.log('share attached'); + } var mongoDataInstance = mongoData(config, db, model); - config.debug && console.log('mongodata initialized'); + if (config.debug) { + console.log('mongodata initialized'); + } shareHandlers(config, model, mongoDataInstance); - config.debug && console.log('shareHandlers attached'); + if (config.debug) { + console.log('shareHandlers attached'); + } var previewInstance = preview(config, mongoDataInstance, helperInstance, markerInstance); - config.debug && console.log('previews initialized'); + if (config.debug) { + console.log('previews initialized'); + } var importerInstance = importer(config, mongoDataInstance, helperInstance, markerInstance); - config.debug && console.log('importer initialized'); + if (config.debug) { + console.log('importer initialized'); + } var handlerInstance = handlers(mongoDataInstance, previewInstance, importerInstance); - config.debug && console.log('handlers initialized'); + if (config.debug) { + console.log('handlers initialized'); + } app = addRoutes(app, handlerInstance, markers, config); - config.debug && console.log('routes added'); + if (config.debug) { + console.log('routes added'); + } server.on('error', function (err) { - config.error && console.log('server error', err); + if (config.error) { + console.error('server error', err); + } }); return server.listen(config.port, function handleServerResult(err) { if (err) { @@ -137,7 +166,9 @@ MongoClient.connect(config.mongo.server, config.mongo.options, function connecti console.error('Server error', err); return process.exit(1); } - config.debug && console.log('routes', app.routes); + if (config.debug) { + console.log('routes', app.routes); + } return console.log('Server running at http://127.0.0.1:', config.port); }); });