mongorilla
Version:
Mongorilla is a simple, clean, and powerful NodeJS based content moderator for MongoDB.
245 lines (207 loc) • 7.65 kB
JavaScript
/*
* handle api endpoints.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId,
_ = require('underscore');
function saveRevisionSnapshot (collection, objectId, user, callback) {
getModel(collection.name)
.findOne({ _id: objectId })
.populate(_(collection.relations).keys().join(' '))
.exec(function (err, fullModel) {
// mongoose hooks doesn't have support for update, so here is the "hook"
var RevisionModel = global.getRevisionModel(collection.name);
var revisionModel = new RevisionModel();
revisionModel.set({
objectId: objectId,
collectionName: collection.name,
user: user.username,
created: new Date(),
modelSnapshot: fullModel.toJSON()
});
revisionModel.save(function (err, revision) {
if (callback) {
callback.apply(null, err, revision);
}
});
});
}
function getCollection(req, res) {
var collectionName = req.route.params.collectionName;
var collection = _(global.config.collections).find(function (col) {
return col.name === collectionName;
});
if (!collection) {
res.status(400);
res.send({ error: 'bad request' });
return;
}
return collection;
};
function checkAcl(req, res) {
var collectionName = req.route.params.collectionName;
var ops = { GET: 'r', POST: 'c', PUT: 'u', DELETE: 'd' };
if (!global.helpers.hasPermission(req.session.user, collectionName, ops[req.method])) {
res.status(403);
res.send({ error: req.session.user.name + ' has no enough permissions for perform this operation' });
return false;
}
return true;
};
exports.get = function (req, res) {
var objectId = req.route.params.objectId,
collection = getCollection(req, res);
if (!collection) {
return;
}
if ('default' === objectId) {
res.send(collection.backboneForms.defaults||{});
} else {
getModel(collection.name)
.findOne({ _id: objectId })
.populate(_(collection.relations).keys().join(' '))
.exec()
.then(function (data) {
res.send(data);
})
.reject(function () {
res.send(arguments);
});
}
};
exports.post = function (req, res) {
var objectId = req.route.params.objectId,
collection = getCollection(req, res);
if (!collection) {
return;
}
var attributes = _.clone(req.body);
var responseData = _.clone(attributes);
_(collection.relations).each(function (data, relKey) {
if (_.isArray(req.body[relKey]) && req.body[relKey].length) {
attributes[relKey] = _(req.body[relKey]).map(function (val, key) {
if ('string' === typeof val ) {
return val;
}
return val['_id'] ? val['_id'].toString() : '';
});
if (0 === attributes[relKey].length) {
delete attributes[relKey];
}
} else if (_.isObject(req.body[relKey]) && req.body[relKey]['_id']) {
attributes[relKey] = req.body[relKey]['_id'].toString();
}
});
delete attributes['_id'];
// TODO skip all attributes not specified in schema
var attributesToSet = global.helpers.toFlat(attributes);
var model = new getModel(collection.name)();
model.set(attributesToSet);
model.set(collection.createdField.key, new global[collection.createdField.type||'Date']());
model.set(collection.updatedField.key, new global[collection.createdField.type||'Date']());
model.save(function (err, model) {
if (err) {
res.send(err);
} else {
var responseData = model.toObject();
delete responseData.__v;
if (collection.revisionable) {
saveRevisionSnapshot(collection, model._id, req.session.user, function (err, revision) {
res.send(responseData);
});
} else {
res.send(responseData);
}
}
});
};
exports.put = function (req, res) {
var objectId = req.route.params.objectId,
collection = getCollection(req, res);
if (!collection) {
return;
}
var attributes = _.clone(req.body);
var responseData = _.clone(attributes);
_(collection.relations).each(function (data, relKey) {
if (_.isArray(req.body[relKey]) && req.body[relKey].length) {
attributes[relKey] = _(req.body[relKey]).map(function (val, key) {
if ('string' === typeof val ) {
return val;
}
return val['_id'] ? val['_id'].toString() : '';
});
if (0 === attributes[relKey].length) {
delete attributes[relKey];
}
} else if (_.isObject(req.body[relKey]) && req.body[relKey]['_id']) {
attributes[relKey] = req.body[relKey]['_id'].toString();
}
});
delete attributes['_id'];
// TODO skip all attributes not specified in schema
var attributesToSet = global.helpers.toFlat(attributes);
attributesToSet[collection.updatedField.key] = new global[collection.createdField.type||'Date']().toISOString();
getModel(collection.name)
.findByIdAndUpdate(objectId, { $set: attributesToSet }, function (err, model) {
if (err) {
res.send(err);
} else {
if (collection.revisionable) {
saveRevisionSnapshot(collection, objectId, req.session.user, function (err, revision) {
res.send(responseData);
});
} else {
res.send(responseData);
}
}
});
};
exports.del = function (req, res) {
var objectId = req.route.params.objectId,
collection = getCollection(req, res);
if (!collection) {
return;
}
getModel(collection.name)
.findByIdAndRemove(objectId, function (err, model) {
if (err) {
res.send(err);
} else {
res.send(model);
}
});
};
exports.getSearch = function (req, res) {
var url = require('url'),
url_parts = url.parse(req.url, true),
q = (url_parts.query.q||'').sanitize().makeSafeForRegex(),
collection = getCollection(req, res);
if (!collection) {
return;
}
var columnsHumanNames = _(collection.fastSearch.columns).map(function (col) {
if (collection.backboneForms.schema[col]) {
return collection.backboneForms.schema[col].title || col;
}
return col;
});
var findParams = global.helpers.toJS(_(collection.fastSearch.find).clone(), function (arg) {
return arg.replace(/\$\{q\}/g, q);
});
getModel(collection.name)
.find(findParams, collection.fastSearch.columns.join(' ') + ' ' + collection.toStringField)
.sort(collection.fastSearch.sort)
.limit(collection.fastSearch.limit)
.exec()
.then(function (results) {
res.send({
collectionName: collection.name,
q: q,
columns: collection.fastSearch.columns,
columnsHumanNames: columnsHumanNames,
data: results
});
});
};