mirror of
/repos/Prototyper.git
synced 2026-02-27 16:12:00 +01:00
moved code into lib folder
This commit is contained in:
25
lib/handlers.js
Normal file
25
lib/handlers.js
Normal file
@@ -0,0 +1,25 @@
|
||||
module.exports = function (mongoDataInstance, previewInstance, importerInstance) {
|
||||
|
||||
function getAttribute(options, callback) {
|
||||
mongoDataInstance.getMongoAttribute(options, callback);
|
||||
}
|
||||
|
||||
function getContent(options, callback) {
|
||||
mongoDataInstance.getMongoContent(options, callback);
|
||||
}
|
||||
|
||||
function getPreviewHTML(html, options, callback) {
|
||||
previewInstance.getPreviewHTML(html, options, callback);
|
||||
}
|
||||
|
||||
function importer(doc, options, callback) {
|
||||
importerInstance.importer(doc, options, callback);
|
||||
}
|
||||
|
||||
return {
|
||||
getAttribute: getAttribute,
|
||||
getContent: getContent,
|
||||
getPreviewHTML: getPreviewHTML,
|
||||
importer: importer
|
||||
}
|
||||
};
|
||||
68
lib/helpers.js
Normal file
68
lib/helpers.js
Normal file
@@ -0,0 +1,68 @@
|
||||
var when = require('when');
|
||||
var _ = require('underscore');
|
||||
|
||||
module.exports = function (markers) {
|
||||
|
||||
function replace(text, marker, getReplacement, once) {
|
||||
var deferred = when.defer();
|
||||
var regExp = new RegExp(markers.prefix + marker + markers.postfix, 'gmi');
|
||||
var matches = text && text.match && text.match(regExp);
|
||||
if (matches) {
|
||||
if (once) {
|
||||
matches = [matches[0]];
|
||||
}
|
||||
var match_promises = [];
|
||||
_.forEach(matches, function handleMatch(result) {
|
||||
var deferred2 = when.defer();
|
||||
match_promises.push(deferred2.promise);
|
||||
getReplacement(result, function resolveReplacement(err, replacement) {
|
||||
if (err) {
|
||||
deferred2.reject(err);
|
||||
} else {
|
||||
var replace_result = {
|
||||
regExp: replacement.regExp || regExp,
|
||||
replacement: replacement.value
|
||||
};
|
||||
deferred2.resolve(replace_result)
|
||||
}
|
||||
})
|
||||
});
|
||||
when.all(
|
||||
match_promises
|
||||
).then(
|
||||
function onSuccess(results) {
|
||||
deferred.resolve(results);
|
||||
},
|
||||
function onFailure(err) {
|
||||
deferred.reject(err);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
deferred.resolve({});
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function handTextManipulation(text, promises, handler, callback) {
|
||||
when.all(
|
||||
promises
|
||||
).then(
|
||||
function onSuccess(all_results) {
|
||||
_.forEach(all_results, function loopResults(results) {
|
||||
_.forEach(results, function handleResult(result) {
|
||||
text = handler(text, result);
|
||||
});
|
||||
});
|
||||
return callback(null, text);
|
||||
},
|
||||
function onFailure(err) {
|
||||
return callback(err);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
replace: replace,
|
||||
handTextManipulation: handTextManipulation
|
||||
}
|
||||
};
|
||||
197
lib/importer.js
Normal file
197
lib/importer.js
Normal file
@@ -0,0 +1,197 @@
|
||||
var when = require('when');
|
||||
var _ = require('underscore');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
module.exports = function (config, mongoInstance, helpers, markers) {
|
||||
|
||||
var import_leftovers_tag = markers.import_leftovers_tag;
|
||||
var import_leftovers_regexp = markers.import_leftovers_regexp;
|
||||
|
||||
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) {
|
||||
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);
|
||||
return new_text;
|
||||
}
|
||||
|
||||
helpers.handTextManipulation(doc,
|
||||
promises,
|
||||
handler,
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
var import_tag = markers.import_tag;
|
||||
var import_regexp = markers.import_regexp;
|
||||
var import_strip_regexp = markers.import_strip_regexp;
|
||||
|
||||
var import_file_tag = markers.import_file_tag;
|
||||
var import_file_regexp = markers.import_file_regexp;
|
||||
|
||||
var replaceMarkers = function (doc, options) {
|
||||
var promises = [];
|
||||
|
||||
promises.push(
|
||||
helpers.replace(doc, import_tag, function handleImportMarker(result, callback) {
|
||||
var parts = import_regexp.exec(result);
|
||||
var context = {
|
||||
collection: parts[1],
|
||||
name: parts[2],
|
||||
attribute: parts[3]
|
||||
};
|
||||
var striped_parts = import_strip_regexp.exec(parts[4]);
|
||||
var sub_doc = striped_parts[1];
|
||||
|
||||
handleImportMarkers(sub_doc, options, function handleLeftover(err, remainder) {
|
||||
if (err) {
|
||||
config.errors && console.log('ERR importer.replaceMarkers import_content_marker', err);
|
||||
return callback(err);
|
||||
}
|
||||
return importRemainder(context, result, remainder, callback);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
promises.push(
|
||||
helpers.replace(doc, import_file_tag, function handleImportFileMarker(result, callback) {
|
||||
var parts = import_file_regexp.exec(result);
|
||||
var filename = path.resolve(config.statics.importer_path, parts[1]);
|
||||
var context = {
|
||||
collection: parts[2],
|
||||
name: parts[3],
|
||||
attribute: parts[4]
|
||||
};
|
||||
fs.readFile(filename, 'utf-8', function handleFileContent(err, sub_doc) {
|
||||
if (err) {
|
||||
config.errors && console.log('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);
|
||||
return callback(err);
|
||||
}
|
||||
return importRemainder(context, result, remainder, callback);
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
64
lib/markers.js
Normal file
64
lib/markers.js
Normal file
@@ -0,0 +1,64 @@
|
||||
module.exports = function markers(config) {
|
||||
var marker_prefix = '<!--\\s*@@';
|
||||
var marker_postfix = '\\s*-->';
|
||||
|
||||
// Preview markers
|
||||
var script_tag = 'script__([A-Za-z0-9]+)_([A-Za-z0-9]+)_([A-Za-z0-9]+)';
|
||||
var script_regexp = new RegExp(marker_prefix + script_tag + marker_postfix);
|
||||
|
||||
var style_tag = 'style__([A-Za-z0-9]+)_([A-Za-z0-9]+)_([A-Za-z0-9]+)';
|
||||
var style_regexp = new RegExp(marker_prefix + style_tag + marker_postfix);
|
||||
|
||||
var less_tag = 'less__([A-Za-z0-9]+)_([A-Za-z0-9]+)_([A-Za-z0-9]+)';
|
||||
var less_regexp = new RegExp(marker_prefix + less_tag + marker_postfix);
|
||||
|
||||
var template_tag = 'template__([A-Za-z0-9]+)_([A-Za-z0-9]+)_([A-Za-z0-9]+)__context__([A-Za-z0-9]+)_([A-Za-z0-9]+)';
|
||||
var template_regexp = new RegExp(marker_prefix + template_tag + marker_postfix);
|
||||
|
||||
var markdown_tag = 'markdown__([A-Za-z0-9]+)_([A-Za-z0-9]+)_([A-Za-z0-9]+)';
|
||||
var markdown_regexp = new RegExp(marker_prefix + markdown_tag + marker_postfix);
|
||||
|
||||
var remove_tag = 'remove_([\\w\\W]*?)_end_remove';
|
||||
//var remove_regexp = new RegExp(remove_tag);
|
||||
|
||||
// Importer markers
|
||||
var import_leftovers_tag = 'import_leftovers__([A-Za-z0-9]+)_([A-Za-z0-9]+)_([A-Za-z0-9]+)';
|
||||
var import_leftovers_regexp = new RegExp(marker_prefix + import_leftovers_tag + marker_postfix);
|
||||
|
||||
var import_tag = 'import__([A-Za-z0-9]+)_([A-Za-z0-9]+)_([A-Za-z0-9]+)_([\\w\\W]*)_end_import__\\1_\\2_\\3';
|
||||
var import_regexp = new RegExp(marker_prefix + import_tag + marker_postfix);
|
||||
var import_strip_regexp = new RegExp(marker_postfix + '([\\w\\W]*)' + marker_prefix);
|
||||
|
||||
var import_file_tag = 'import_file__([A-Za-z0-9.\/]+)__into__([A-Za-z0-9]+)_([A-Za-z0-9]+)_([A-Za-z0-9]+)';
|
||||
var import_file_regexp = new RegExp(marker_prefix + import_file_tag + marker_postfix);
|
||||
|
||||
|
||||
function createTag(type, collection, name, attribute) {
|
||||
return '<!-- @@' + type + '__' + collection + '_' + name + '_' + attribute + ' -->';
|
||||
}
|
||||
|
||||
return {
|
||||
prefix: marker_prefix,
|
||||
postfix: marker_postfix,
|
||||
createTag:createTag,
|
||||
script_tag:script_tag,
|
||||
script_regexp:script_regexp,
|
||||
style_tag:style_tag,
|
||||
style_regexp:style_regexp,
|
||||
less_tag:less_tag,
|
||||
less_regexp:less_regexp,
|
||||
template_tag:template_tag,
|
||||
template_regexp:template_regexp,
|
||||
markdown_tag:markdown_tag,
|
||||
markdown_regexp:markdown_regexp,
|
||||
remove_tag:remove_tag,
|
||||
// remove_regexp:remove_regexp,
|
||||
import_leftovers_tag:import_leftovers_tag,
|
||||
import_leftovers_regexp:import_leftovers_regexp,
|
||||
import_tag:import_tag,
|
||||
import_regexp:import_regexp,
|
||||
import_strip_regexp:import_strip_regexp,
|
||||
import_file_tag:import_file_tag,
|
||||
import_file_regexp:import_file_regexp
|
||||
}
|
||||
};
|
||||
425
lib/mongodata.js
Normal file
425
lib/mongodata.js
Normal file
@@ -0,0 +1,425 @@
|
||||
var ObjectID = require('mongodb').ObjectID;
|
||||
var _ = require('underscore');
|
||||
|
||||
|
||||
module.exports = function (config, db, shareModel) {
|
||||
|
||||
/*
|
||||
options:
|
||||
* collection (mandatory)
|
||||
* query (mandatory)
|
||||
*/
|
||||
function getMongoContent(options, callback) {
|
||||
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);
|
||||
return callback(err);
|
||||
}
|
||||
if (!options.query) {
|
||||
return callback(new Error('Data not found ' + options.collection + '/ missing query'), null, col);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
return col.findOne(options.query, function foundOne(err, result) {
|
||||
if (err) {
|
||||
config.errors && console.log('ERR4 getMongoContent', err);
|
||||
return callback(err);
|
||||
}
|
||||
if (!result) {
|
||||
return callback(new Error('Data not found ' + options.collection + '/' + JSON.stringify(options.query)), null, col);
|
||||
}
|
||||
return callback(null, result, col);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var ensuring = false;
|
||||
|
||||
function ensureContent(options, callback) {
|
||||
if (ensuring) {
|
||||
//noinspection JSUnresolvedFunction
|
||||
setImmediate(function rescheduling() {
|
||||
config.debug && console.log('Ensuring, rescheduling', options);
|
||||
return ensureContent(options, callback);
|
||||
});
|
||||
} else {
|
||||
ensuring = true;
|
||||
if (!options.query) {
|
||||
options.query = {
|
||||
name: options.name
|
||||
}
|
||||
}
|
||||
function stopEnsuring(err, result, col) {
|
||||
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) {
|
||||
var keys = _.keys(data); // reset all attributes;
|
||||
return updateShareDocument(documentId, data, keys, function updatedShareDocument() {
|
||||
stopEnsuring(err, content_result, col);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return stopEnsuring(err);
|
||||
}
|
||||
} else {
|
||||
return stopEnsuring(null, result, col);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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);
|
||||
ensureContent(options, function document(err, result, col) {
|
||||
if (err) {
|
||||
config.errors && console.log('ERR1 setMongoAttribute', err);
|
||||
return callback(err);
|
||||
}
|
||||
var attribute_options = {
|
||||
collection: options.collection,
|
||||
name: result.name + '.' + options.attribute
|
||||
};
|
||||
if (result.hasOwnProperty(options.attribute)
|
||||
&& result[options.attribute].guid) {
|
||||
attribute_options.query = {
|
||||
_id: result[options.attribute].guid
|
||||
};
|
||||
} else {
|
||||
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);
|
||||
return ensureContent(attribute_options, function attribute(err, attribute_result) {
|
||||
if (err) {
|
||||
config.errors && console.log('ERR2 setMongoAttribute ensureContent', err);
|
||||
return callback(err);
|
||||
}
|
||||
var updateContent = true;
|
||||
if (result[options.attribute]) {
|
||||
if (attribute_result._id.toString() == String(result[options.attribute].guid)) {
|
||||
updateContent = false;
|
||||
} else {
|
||||
result[options.attribute].guid = attribute_result._id;
|
||||
}
|
||||
} else {
|
||||
result[options.attribute] = { guid: attribute_result._id };
|
||||
}
|
||||
|
||||
attribute_result.parent = result._id;
|
||||
attribute_result.name = result.name + '.' + options.attribute;
|
||||
attribute_result[options.attribute] = data;
|
||||
if (options.operation) {
|
||||
attribute_result.version = options.operation.v;
|
||||
}
|
||||
return saveData(col, attribute_result, function saved(err) {
|
||||
if (err) {
|
||||
config.errors && console.log('ERR3 setMongoAttribute', err);
|
||||
return callback(err);
|
||||
}
|
||||
var documentId = 'json:' + options.collection + ':' + result.name;
|
||||
var type = options.type || 'text';
|
||||
var attributeDocumentId = type + ':' + options.collection + ':' + result.name + ':' + options.attribute;
|
||||
var keys = null;
|
||||
var share_data = null;
|
||||
if (type == 'json') {
|
||||
keys = _.keys(attribute_result); // reset all attributes;
|
||||
share_data = attribute_result;
|
||||
} else {
|
||||
keys = [attribute_result.name];
|
||||
share_data = data;
|
||||
}
|
||||
if (options.no_share) {
|
||||
keys = null;
|
||||
}
|
||||
return updateShareDocument(attributeDocumentId, share_data, keys, function updatedShareAttribute() {
|
||||
if (updateContent) {
|
||||
return updateData(col, result, function saved(err) {
|
||||
if (err) {
|
||||
config.errors && console.log('ERR3 setMongoAttribute', err);
|
||||
return callback(err);
|
||||
}
|
||||
var path = [options.attribute, 'guid']; // reset just guid attribute;
|
||||
return updateShareDocumentPath(documentId, result, path, function updatedShareContent() {
|
||||
return callback(null, attribute_result, col);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return callback(null, attribute_result, col);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
setMongoAttribute: setMongoAttribute,
|
||||
setMongoContent: setMongoContent,
|
||||
ensureContent: ensureContent,
|
||||
updateShareDocument: updateShareDocument
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
258
lib/preview.js
Normal file
258
lib/preview.js
Normal file
@@ -0,0 +1,258 @@
|
||||
var Handlebars = require('handlebars');
|
||||
var markdown = require('markdown').markdown;
|
||||
var _ = require('underscore');
|
||||
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
|
||||
);
|
||||
};
|
||||
|
||||
var script_tag = markers.script_tag;
|
||||
var script_regexp = markers.script_regexp;
|
||||
|
||||
var style_tag = markers.style_tag;
|
||||
var style_regexp = markers.style_regexp;
|
||||
|
||||
var less_tag = markers.less_tag;
|
||||
var less_regexp = markers.less_regexp;
|
||||
|
||||
var template_tag = markers.template_tag;
|
||||
var template_regexp = markers.template_regexp;
|
||||
|
||||
var markdown_tag = markers.markdown_tag;
|
||||
var markdown_regexp = markers.markdown_regexp;
|
||||
|
||||
var remove_tag = markers.remove_tag;
|
||||
//var remove_regexp = markers.remove_regexp;
|
||||
|
||||
var replaceMarkers = function (html, options) {
|
||||
|
||||
var promises = [];
|
||||
|
||||
// Script tag handling
|
||||
promises.push(
|
||||
helpers.replace(html, script_tag, function handleScriptMarker(result, callback) {
|
||||
var parts = script_regexp.exec(result);
|
||||
var context = {
|
||||
collection: parts[1],
|
||||
name: parts[2],
|
||||
attribute: parts[3]
|
||||
};
|
||||
return callback(null, {
|
||||
regExp: new RegExp(result, 'gmi'),
|
||||
value: '<script src="' + config.api.content + '/' + context.collection + '/' + context.name + '/' + context.attribute + '.js" type="text/javascript" charset="utf-8"></script>'
|
||||
});
|
||||
}));
|
||||
|
||||
// Style tag handling
|
||||
promises.push(
|
||||
helpers.replace(html, style_tag, function handleStyleMarker(result, callback) {
|
||||
var parts = style_regexp.exec(result);
|
||||
var context = {
|
||||
collection: parts[1],
|
||||
name: parts[2],
|
||||
attribute: parts[3]
|
||||
};
|
||||
return callback(null, {
|
||||
regExp: new RegExp(result, 'gmi'),
|
||||
value: '<link href="' + config.api.content + '/' + context.collection + '/' + context.name + '/' + context.attribute + '.css" media="all" rel="stylesheet" type="text/css">'
|
||||
});
|
||||
}));
|
||||
|
||||
// Less tag handling
|
||||
promises.push(
|
||||
helpers.replace(html, less_tag, function handleStyleMarker(result, callback) {
|
||||
var parts = less_regexp.exec(result);
|
||||
var context = {
|
||||
collection: parts[1],
|
||||
name: parts[2],
|
||||
attribute: parts[3]
|
||||
};
|
||||
return callback(null, {
|
||||
regExp: new RegExp(result, 'gmi'),
|
||||
value: '<link href="' + config.api.content + '/' + context.collection + '/' + context.name + '/' + context.attribute + '.less" media="all" rel="stylesheet/less" type="text/css">'
|
||||
});
|
||||
}));
|
||||
|
||||
// Template tag handling
|
||||
promises.push(
|
||||
helpers.replace(html, template_tag, function handleTemplateMarker(result, callback) {
|
||||
var parts = template_regexp.exec(result);
|
||||
var template = {
|
||||
collection: parts[1],
|
||||
name: parts[2],
|
||||
attribute: parts[3],
|
||||
query: { name: parts[2]}
|
||||
};
|
||||
var context = {
|
||||
collection: parts[4],
|
||||
name: parts[5],
|
||||
query: { name: parts[5]},
|
||||
req: options.req
|
||||
};
|
||||
return mongoDataInstance.getMongoContent(context, function handleContext(err, context_result) {
|
||||
if (err) {
|
||||
config.errors && console.log('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);
|
||||
return callback(err);
|
||||
}
|
||||
var compiled_template = null;
|
||||
var keys_to_collect = {};
|
||||
|
||||
function collectKey(key) {
|
||||
return function () {
|
||||
if (keys_to_collect.hasOwnProperty(key)) {
|
||||
return keys_to_collect[key];
|
||||
} else {
|
||||
keys_to_collect[key] = null;
|
||||
return "waiting for content";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handlebars is synchronous ouch !!
|
||||
var handlebars = Handlebars.create();
|
||||
_.forEach(_.keys(context_result), function (key) {
|
||||
handlebars.registerHelper(key, function () {
|
||||
if (context_result[key].guid) {
|
||||
return collectKey(key)();
|
||||
}
|
||||
return context_result[key];
|
||||
});
|
||||
});
|
||||
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);
|
||||
}
|
||||
var extendHandlebars_context = function (result) {
|
||||
var handlebars = {};
|
||||
_.forEach(_.keys(result), function (key) {
|
||||
if (result[key].guid) {
|
||||
handlebars[key] = collectKey(key);
|
||||
} else {
|
||||
handlebars[key] = result[key];
|
||||
}
|
||||
});
|
||||
return handlebars;
|
||||
};
|
||||
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);
|
||||
}
|
||||
var promises = [];
|
||||
_.forEach(_.keys(keys_to_collect), function gatherKeyValues(key) {
|
||||
var deferred = when.defer();
|
||||
var promise = deferred.promise;
|
||||
promises.push(promise);
|
||||
var attribute_context = {
|
||||
collection: context.collection,
|
||||
attribute: key,
|
||||
query: { _id: context_result._id}
|
||||
};
|
||||
return mongoDataInstance.getMongoAttribute(attribute_context, function cacheTemplateKey(err, template_key_result) {
|
||||
if (err) {
|
||||
config.errors && console.log('ERR handlebar.registerHelper getMongoAttribute', err);
|
||||
deferred.reject(err);
|
||||
}
|
||||
var value = template_key_result[key];
|
||||
keys_to_collect[key] = value;
|
||||
deferred.resolve(value);
|
||||
});
|
||||
});
|
||||
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);
|
||||
return callback(err);
|
||||
}
|
||||
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);
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null, {
|
||||
regExp: new RegExp(result, 'gmi'),
|
||||
value: preview_html
|
||||
});
|
||||
});
|
||||
},
|
||||
function onFailure(err) {
|
||||
config.errors && console.log('ERR template_tag resolving promises', err);
|
||||
return callback(err);
|
||||
}
|
||||
)
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
// Markdown tag handling
|
||||
promises.push(
|
||||
helpers.replace(html, markdown_tag, function handleMarkDownMarker(result, callback) {
|
||||
var parts = markdown_regexp.exec(result);
|
||||
var attribute = {
|
||||
collection: parts[1],
|
||||
name: parts[2],
|
||||
attribute: parts[3],
|
||||
query: { name: parts[2] }
|
||||
};
|
||||
return mongoDataInstance.getMongoAttribute(attribute, function handleMarkdownContent(err, markdown_result) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
var html = markdown.toHTML(markdown_result[attribute.attribute]);
|
||||
return callback(null, {
|
||||
regExp: new RegExp(result, 'gmi'),
|
||||
value: html
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
// Remove tag handling
|
||||
promises.push(
|
||||
helpers.replace(html, remove_tag, function handleRemoveMarker(result, callback) {
|
||||
return callback(null, {
|
||||
regExp: null,
|
||||
value: ""
|
||||
});
|
||||
}, true));
|
||||
|
||||
return promises;
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
getPreviewHTML: getPreviewHTML,
|
||||
_replaceMarkers: replaceMarkers
|
||||
};
|
||||
};
|
||||
|
||||
35
lib/responder.js
Normal file
35
lib/responder.js
Normal file
@@ -0,0 +1,35 @@
|
||||
var mimetypes = {
|
||||
'js': 'application/javascript',
|
||||
'html': 'text/html',
|
||||
'md': 'text/html',
|
||||
'text': 'text/plain',
|
||||
'css': 'text/css',
|
||||
'less': 'text/css'
|
||||
};
|
||||
|
||||
var getMimeType = function (ext) {
|
||||
if (mimetypes[ext]) {
|
||||
return mimetypes[ext];
|
||||
}
|
||||
|
||||
return mimetypes.text;
|
||||
};
|
||||
|
||||
module.exports = function (options, res, next) {
|
||||
return function responder(err, result) {
|
||||
if (err) {
|
||||
console.log('ERR responder', options, err);
|
||||
if (/Data not found*/.test(err.message)) {
|
||||
res.status(404);
|
||||
}
|
||||
return next(err);
|
||||
}
|
||||
var contentType = getMimeType(options.ext);
|
||||
res.setHeader('Content-Type', contentType);
|
||||
var content = result;
|
||||
if (options.attribute) {
|
||||
content = result[options.attribute];
|
||||
}
|
||||
return res.send(content);
|
||||
};
|
||||
};
|
||||
142
lib/routes.js
Normal file
142
lib/routes.js
Normal file
@@ -0,0 +1,142 @@
|
||||
var responder = require('./responder.js');
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
module.exports = function (app, handlers, markers, config) {
|
||||
|
||||
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)');
|
||||
var options = {
|
||||
collection: req.params.collection,
|
||||
attribute: req.params.attribute,
|
||||
ext: req.params.ext,
|
||||
query: {_id: req.params.guid}
|
||||
};
|
||||
handlers.getAttribute(options,
|
||||
responder(options, res, next)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
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)');
|
||||
var options = {
|
||||
collection: req.params.collection,
|
||||
ext: req.params.ext,
|
||||
query: {_id: req.params.guid}
|
||||
};
|
||||
handlers.getContent(options,
|
||||
responder(options, res, next)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
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)');
|
||||
var options = {
|
||||
collection: req.params.collection,
|
||||
attribute: req.params.attribute,
|
||||
ext: req.params.ext,
|
||||
query: {name: req.params.name}
|
||||
};
|
||||
handlers.getAttribute(options,
|
||||
responder(options, res, next)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
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)');
|
||||
var options = {
|
||||
collection: req.params.collection,
|
||||
ext: req.params.ext,
|
||||
query: {name: req.params.name}
|
||||
};
|
||||
handlers.getContent(options,
|
||||
responder(options, res, next)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
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)');
|
||||
var options = {
|
||||
collection: req.params.collection,
|
||||
ext: req.params.ext,
|
||||
query: {name: req.params.name},
|
||||
req: { query: req.query || {},
|
||||
headers: req.headers
|
||||
}
|
||||
};
|
||||
if (options.ext == 'md') {
|
||||
var attribute_parts = options.query.name.split('.');
|
||||
var markdownDocument = markers.createTag('markdown',options.collection, attribute_parts[0], attribute_parts[1]);
|
||||
return handlers.getPreviewHTML(markdownDocument, { req: options.req },
|
||||
responder(options, res, next)
|
||||
);
|
||||
}
|
||||
return handlers.getContent(options, function handleResult(err, result) {
|
||||
if (err) {
|
||||
return responder(options, res, next)(err, result);
|
||||
}
|
||||
if (result) {
|
||||
var attribute_parts = options.query.name.split('.');
|
||||
var attribute = attribute_parts[attribute_parts.length - 1];
|
||||
var attribute_value = result[attribute];
|
||||
if (attribute_value) {
|
||||
options.name = attribute_parts[0];
|
||||
var preview_options = {
|
||||
collection: options.collection,
|
||||
name: options.name,
|
||||
attribute: attribute,
|
||||
query: {_id: result._id},
|
||||
req: options.req
|
||||
};
|
||||
|
||||
config.debug && console.log('getPreviewContent content', attribute_value);
|
||||
return handlers.getPreviewHTML(attribute_value, preview_options,
|
||||
responder(options, res, next)
|
||||
);
|
||||
} else {
|
||||
return next();
|
||||
}
|
||||
} else {
|
||||
return next();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
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);
|
||||
fs.readFile(filename, 'utf-8', function handleFileContent(err, sub_doc) {
|
||||
if (err) {
|
||||
config.errors && console.log('ERR readFile', filename, err);
|
||||
next(err);
|
||||
}
|
||||
// process with leftover marker support
|
||||
var options = {};
|
||||
handlers.importer(sub_doc, options,
|
||||
responder(options, res, next)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
return app;
|
||||
};
|
||||
18
lib/share.js
Normal file
18
lib/share.js
Normal file
@@ -0,0 +1,18 @@
|
||||
var ShareJS = require('share');
|
||||
|
||||
module.exports = function (config, app, db) {
|
||||
// share wraps express app with http.Server
|
||||
if (config
|
||||
&& config.share
|
||||
&& config.share.db
|
||||
&& config.share.db.type == 'mongo') {
|
||||
config.share.db.client = db;
|
||||
}
|
||||
var server = ShareJS.server.attach(app, config.share);
|
||||
var model = app.model;
|
||||
|
||||
return {
|
||||
server: server,
|
||||
model: model
|
||||
};
|
||||
};
|
||||
201
lib/shareHandlers.js
Normal file
201
lib/shareHandlers.js
Normal file
@@ -0,0 +1,201 @@
|
||||
module.exports = function (config, model, mongoDataInstance) {
|
||||
var timers = {};
|
||||
|
||||
function handleMongoGetResult(options) {
|
||||
function handleResult(err, result) {
|
||||
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');
|
||||
result = {};
|
||||
if (options.attribute) {
|
||||
if (options.type == 'json') {
|
||||
result[options.attribute] = {};
|
||||
} else {
|
||||
result[options.attribute] = "";
|
||||
}
|
||||
}
|
||||
notFound = true;
|
||||
} else {
|
||||
config.errors && console.log('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);
|
||||
var data = result;
|
||||
if (options.attribute) {
|
||||
data = result[options.attribute];
|
||||
}
|
||||
var version = 0;
|
||||
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') {
|
||||
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 (error) {
|
||||
options.error && console.log('ERR2 handleMongoGetResult', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handleResult;
|
||||
}
|
||||
|
||||
model.on('create', function populateDocument(documentId, data) {
|
||||
config.debug && console.log('Populating a doc in channel', documentId, data);
|
||||
var splitId = documentId.split(':');
|
||||
var options = {
|
||||
documentId: documentId,
|
||||
type: splitId[0],
|
||||
collection: splitId[1],
|
||||
attribute: null
|
||||
};
|
||||
if (splitId.length == 4) {
|
||||
// options.query = {_id: splitId[2]};
|
||||
options.query = {name: splitId[2]};
|
||||
options.attribute = splitId[3];
|
||||
mongoDataInstance.getMongoAttribute(options, handleMongoGetResult(options));
|
||||
} else {
|
||||
options.query = {name: splitId[2]};
|
||||
mongoDataInstance.getMongoContent(options, handleMongoGetResult(options));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
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);
|
||||
return callback && callback(err);
|
||||
}
|
||||
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);
|
||||
if (error) {
|
||||
config.error && console.log('ERR2 handleMongoSetResult', error);
|
||||
return callback && callback(error);
|
||||
}
|
||||
return callback && callback(null, version);
|
||||
});
|
||||
} else {
|
||||
return callback(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
return handleResult;
|
||||
}
|
||||
|
||||
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);
|
||||
return callback(err);
|
||||
}
|
||||
config.debug && console.log('current', current, 'result', result);
|
||||
return callback(null, null);
|
||||
}
|
||||
|
||||
return handleResult;
|
||||
}
|
||||
|
||||
|
||||
function handleSetTimeout(documentId) {
|
||||
return function saveContent() {
|
||||
var args = timers[documentId];
|
||||
delete timers[documentId];
|
||||
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);
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
function handleSetAttributeTimeout(documentId) {
|
||||
return function saveAttribute() {
|
||||
var args = timers[documentId];
|
||||
delete timers[documentId];
|
||||
config.debug && console.log('running timer', documentId);
|
||||
var data = args.current;
|
||||
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);
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
// '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;
|
||||
|
||||
var splitId = documentId.split(':');
|
||||
var options = {
|
||||
documentId: documentId,
|
||||
type: splitId[0],
|
||||
collection: splitId[1],
|
||||
name: splitId[2],
|
||||
attribute: null,
|
||||
operation: operation,
|
||||
no_share: true // prevent circular updates.
|
||||
};
|
||||
var timer = {
|
||||
current: current,
|
||||
options: options
|
||||
};
|
||||
var attribute = false;
|
||||
if (splitId.length == 4) {
|
||||
// options.query = {_id: splitId[2]};
|
||||
options.query = {name: splitId[2]};
|
||||
options.attribute = splitId[3];
|
||||
attribute = true;
|
||||
} else {
|
||||
options.query = {name: splitId[2]};
|
||||
}
|
||||
if (timers[documentId]) {
|
||||
timer.timer_id = timers[documentId].timer_id;
|
||||
timers[documentId] = timer;
|
||||
config.debug && console.log('resetting timer', documentId);
|
||||
} else {
|
||||
timers[documentId] = timer;
|
||||
if (attribute) {
|
||||
timer.timer_id = setTimeout(
|
||||
handleSetAttributeTimeout(documentId),
|
||||
config.savedelay);
|
||||
} else {
|
||||
timer.timer_id = setTimeout(
|
||||
handleSetTimeout(documentId),
|
||||
config.savedelay);
|
||||
}
|
||||
config.debug && console.log('setting timer', documentId);
|
||||
}
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user