339 lines
10 KiB
JavaScript
339 lines
10 KiB
JavaScript
|
var logger = require('winston').loggers.get('main');
|
||
|
var clone = require('clone');
|
||
|
var fs = require('fs');
|
||
|
var ejs = require('ejs');
|
||
|
var xmlmapping = require('xml-mapping');
|
||
|
var rawbody = require('raw-body');
|
||
|
var typeis = require('type-is');
|
||
|
var mcrud = require('crud-mongoose');
|
||
|
var ncrud = require('node-crud');
|
||
|
var mongoose = require('mongoose');
|
||
|
var buildView = require('./build-view');
|
||
|
|
||
|
exports.bodyParserXml = function() {
|
||
|
return function(req, res, next) {
|
||
|
if (req._body) return next();
|
||
|
req.body = req.body || {};
|
||
|
|
||
|
if (!typeis(req, 'xml')) return next();
|
||
|
|
||
|
// flag as parsed
|
||
|
req._body = true;
|
||
|
|
||
|
// parse
|
||
|
rawbody(req, {
|
||
|
limit: options.limit || '100kb',
|
||
|
length: req.headers['content-length'],
|
||
|
encoding: 'utf8'
|
||
|
}, function (err, buf) {
|
||
|
if (err) return next(err);
|
||
|
|
||
|
if (0 == buf.length) {
|
||
|
return next(error(400, 'invalid xml, empty body'));
|
||
|
}
|
||
|
try {
|
||
|
req.body = xmlmapping.dump(buf/*, options.reviver*/);
|
||
|
} catch (err){
|
||
|
err.body = buf;
|
||
|
err.status = 400;
|
||
|
return next(err);
|
||
|
}
|
||
|
next();
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var renderTemplateDataRead = function(tview, exportType, contentType, model, projection) {
|
||
|
return function(data, query, cb) {
|
||
|
var res = this.response;
|
||
|
res.set('Content-Type', contentType);
|
||
|
|
||
|
var cursor, fields;
|
||
|
if (query.hasOwnProperty('fields')) {
|
||
|
fields = query.fields;
|
||
|
delete query.fields;
|
||
|
}
|
||
|
delete query.export;
|
||
|
cursor = model.findOne(query);
|
||
|
cursor.select(mcrud.tools.select(projection, fields));
|
||
|
cursor.lean().exec(function(err,doc) {
|
||
|
if (err) {
|
||
|
cb(err || 'error in stream');
|
||
|
return;
|
||
|
}
|
||
|
if (doc == null) {
|
||
|
cb('no data'); // TODO: error is still in json...
|
||
|
return;
|
||
|
}
|
||
|
//var templateReadHeader = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/read-header.ejs', 'utf8');
|
||
|
var templateReadRecord = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/read-record.ejs', 'utf8');
|
||
|
//var templateReadFooter = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/read-footer.ejs', 'utf8');
|
||
|
res.write(ejs.render(templateReadRecord,{
|
||
|
tview: tview,
|
||
|
record: doc,
|
||
|
}));
|
||
|
res.end();
|
||
|
|
||
|
//cb(); // FIXME
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var renderTemplateDataList = function(tview, exportType, contentType) {
|
||
|
return function(res, cursor, cb) {
|
||
|
res.set('Content-Type', contentType);
|
||
|
|
||
|
var templateHeader = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/list-header.ejs', 'utf8');
|
||
|
var templateRecord = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/list-record.ejs', 'utf8');
|
||
|
var templateFooter = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/list-footer.ejs', 'utf8');
|
||
|
|
||
|
res.write(ejs.render(templateHeader,{
|
||
|
tview: tview,
|
||
|
}));
|
||
|
cursor.stream()
|
||
|
.on('data', function(doc) {
|
||
|
res.write(ejs.render(templateRecord,{
|
||
|
tview: tview,
|
||
|
record: doc,
|
||
|
}));
|
||
|
})
|
||
|
.on('error', function(e) {
|
||
|
cb(e || 'error in stream');
|
||
|
})
|
||
|
.on('close', function() {
|
||
|
res.write(ejs.render(templateFooter,{
|
||
|
tview: tview,
|
||
|
}));
|
||
|
res.end();
|
||
|
cb();
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
exports.injectExportFormat = function(apiBase) {
|
||
|
return function ( req, res, next ) {
|
||
|
if (req.url.indexOf(apiBase) >= 0) {
|
||
|
if (req.url.indexOf('xml') > 0) {
|
||
|
req.query['export'] = 'xml';
|
||
|
} else if (req.url.indexOf('csv') > 0) {
|
||
|
req.query['export'] = 'csv';
|
||
|
} else if (req.url.indexOf('rss') > 0) {
|
||
|
req.query['export'] = 'rss';
|
||
|
}
|
||
|
if (req.url.indexOf('json') == 0) {
|
||
|
console.log('inject export type: '+req.query['export']);
|
||
|
}
|
||
|
}
|
||
|
next();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var _ = require('underscore');
|
||
|
|
||
|
var filterQueryList = function (model) {
|
||
|
return mcrud.parseQuery()
|
||
|
.defaults({ limit: '10' })
|
||
|
.overrides({})
|
||
|
.maxes({ limit: 1000 });
|
||
|
//.removes()
|
||
|
}
|
||
|
|
||
|
var filterDataUpdate = function (model) {
|
||
|
return mcrud.parseData()
|
||
|
overrides({});
|
||
|
//.removes('auth')
|
||
|
//.overrides({ updated: Date.now })
|
||
|
//.defaults({ 'info.gender': 'M' }))
|
||
|
}
|
||
|
|
||
|
function allowCrudType(tview,tcrudType) {
|
||
|
return tview[tcrudType].tenable; // todo add roles
|
||
|
}
|
||
|
|
||
|
//var rssXNodeMap = function(link,feed,data) {
|
||
|
// feed.addNewItem(data.net_id, link+'/ui/XNode/read/'+data._id, data.changed_data, data.net_id+' id', {});
|
||
|
//}
|
||
|
|
||
|
var sendRedirect = function (location) {
|
||
|
if (!location) {
|
||
|
throw new Error('no location');
|
||
|
}
|
||
|
return function(req, res) {
|
||
|
res.redirect(location);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var renderCrudView = function (tview) {
|
||
|
return function (req, res, next) {
|
||
|
var result = {
|
||
|
tview: tview,
|
||
|
}
|
||
|
res.json({
|
||
|
data: result
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var renderCrudController = function (tview, thtmlPrefix, tapiPrefix) {
|
||
|
return function (req, res, next) {
|
||
|
res.set('Content-Type', 'text/javascript');
|
||
|
res.render('node-ff-tcrud/angular/controller',{
|
||
|
tview: tview,
|
||
|
thtmlPrefix: thtmlPrefix,
|
||
|
tapiPrefix: tapiPrefix,
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var renderCrudTemplate = function (tview,paction) {
|
||
|
return function (req, res, next) {
|
||
|
res.render('node-ff-tcrud/angular/'+paction+'/'+req.params.action,{
|
||
|
tview: tview,
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var buildCrud = function (server,tcrud) {
|
||
|
|
||
|
if (!tcrud.tenable || !tcrud.tmodel) {
|
||
|
logger.info('disabled server: '+tcrud.tid);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var tview = buildView.createTCrudView(tcrud /*, fetchCrudRoles()*/);
|
||
|
var model = mongoose.model( tcrud.tmodel );
|
||
|
|
||
|
// Export tdebug
|
||
|
var uriDebug = tcrud.tmeta.tserver.tslug + '/' +buildView.createBaseApiUri(tview,'json') + '/_debug/';
|
||
|
var tcrudClone = clone(tcrud);
|
||
|
tcrudClone.tparent = null; // rm loop: tparent.tchilds[] = this
|
||
|
server.get(uriDebug + 'tview', renderCrudView(tview));
|
||
|
server.get(uriDebug + 'tcrud', renderCrudView(tcrudClone));
|
||
|
|
||
|
if (_.contains(tview.tmeta.tserver.texports,'json')) {
|
||
|
|
||
|
if (allowCrudType(tview,'tlist')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tlist')).Read()
|
||
|
.pipe(filterQueryList(model))
|
||
|
.pipe(mcrud.findAll(model).stream());
|
||
|
}
|
||
|
if (allowCrudType(tview,'tcreate')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tcreate')).Create()
|
||
|
.pipe(mcrud.createNew(model));
|
||
|
}
|
||
|
if (allowCrudType(tview,'tread')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tread') + '/:_id').Read()
|
||
|
.pipe(mcrud.findOne(model));
|
||
|
}
|
||
|
if (allowCrudType(tview,'tedit')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tedit') + '/:_id').Update()
|
||
|
.pipe(filterDataUpdate(model))
|
||
|
.pipe(mcrud.updateOne (model));
|
||
|
}
|
||
|
if (allowCrudType(tview,'tdelete')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tdelete') +'/:_id').Delete()
|
||
|
.pipe(mcrud.removeOne(model));
|
||
|
}
|
||
|
if (allowCrudType(tview,'tcount')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tcount')).Read()
|
||
|
.pipe(filterQueryList(model))
|
||
|
.pipe(mcrud.findAll(model).stream());
|
||
|
}
|
||
|
if (allowCrudType(tview,'tverify')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tverify') + '/:_id').Update()
|
||
|
.pipe(mcrud.findOne(model));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_.contains(tview.tmeta.tserver.texports,'xml')) {
|
||
|
if (allowCrudType(tview,'tlist')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tlist')).Read()
|
||
|
.pipe(filterQueryList(model))
|
||
|
.pipe(mcrud.findAll(model).stream().exports({ xml: renderTemplateDataList(tview,'xml','text/xml') }));
|
||
|
}
|
||
|
if (allowCrudType(tview,'tcreate')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tcreate')).Create()
|
||
|
.pipe(mcrud.createNew(model));
|
||
|
}
|
||
|
if (allowCrudType(tview,'tread')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tread') +'/:_id').Read()
|
||
|
.pipe(renderTemplateDataRead(tview,'xml','text/xml',model));
|
||
|
}
|
||
|
if (allowCrudType(tview,'tedit')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tedit')+'/:_id').Update()
|
||
|
.pipe(filterDataUpdate(model))
|
||
|
.pipe(mcrud.updateOne (model));
|
||
|
}
|
||
|
if (allowCrudType(tview,'tdelete')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tdelete')+'/:_id').Delete()
|
||
|
.pipe(mcrud.removeOne (model));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_.contains(tview.tmeta.tserver.texports,'csv')) {
|
||
|
if (allowCrudType(tview,'tlist')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'csv','tlist')).Read()
|
||
|
.pipe(filterQueryList(model))
|
||
|
.pipe(mcrud.findAll(model).stream().exports({ csv: renderTemplateDataList(tview,'csv','text/csv') }));
|
||
|
}
|
||
|
if (allowCrudType(tview,'tread')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'csv','tread') +'/:_id').Read()
|
||
|
.pipe(renderTemplateDataRead(tview,'csv','text/csv',model));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_.contains(tview.tmeta.tserver.texports,'rss')) {
|
||
|
if (allowCrudType(tview,'tlist')) {
|
||
|
ncrud.entity(buildView.createBaseApiUri(tview,'rss','tlist')).Read()
|
||
|
.pipe(mcrud.parseQuery()
|
||
|
.defaults({ limit: '10' })
|
||
|
.maxes({ limit: 50 })
|
||
|
)
|
||
|
.pipe(mcrud.findAll(model)
|
||
|
.stream()
|
||
|
.exports({ rss: renderTemplateDataList(tview,'rss','text/xml') })
|
||
|
);
|
||
|
}
|
||
|
//.exports({ rss: exports.exportRss('todo',tview.xid,rssXNodeMap) })
|
||
|
}
|
||
|
if (_.contains(tview.tmeta.tserver.texports,'angular')) {
|
||
|
|
||
|
var uriPrefix = tcrud.tmeta.tserver.tslug + '/' + buildView.createBaseApiUri(tview,'angular');
|
||
|
var thtmlPrefix = uriPrefix + '/' + tview.tmeta.texport.angular.thtml;
|
||
|
var tapiPrefix = tcrud.tmeta.tserver.tslug + '/' +buildView.createBaseApiUri(tview,'json');
|
||
|
|
||
|
//server.get('/ui/include/crud/:name/:action', XViewInclude.renderTemplateCrud);
|
||
|
//server.get('/ui/include/js/controller/:name', XViewInclude.renderCrudController);
|
||
|
|
||
|
server.get(uriPrefix + '/thtml/crud/:action', renderCrudTemplate(tview,'thtml/crud/'));
|
||
|
server.get(uriPrefix + '/controller.js', renderCrudController(tview,thtmlPrefix,tapiPrefix));
|
||
|
//server.get(uriPrefix + '/service.js', renderCrudService(tview))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function walkViews(server,tcrud) {
|
||
|
//logger.debug('walk views: '+tcrud.tid);
|
||
|
if (tcrud.tparent) {
|
||
|
buildCrud(server,tcrud);
|
||
|
}
|
||
|
for (var i = 0; i < tcrud.tchilds.length; i++) {
|
||
|
walkViews(server,tcrud.tchilds[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function buildCrudApi(server) { // todo add return function
|
||
|
|
||
|
troot = server.get('ff_root_tcrud_view');
|
||
|
walkViews(server,troot);
|
||
|
|
||
|
server.use(exports.injectExportFormat(troot.tmeta.tserver.tslug));
|
||
|
server.use(exports.bodyParserXml());
|
||
|
ncrud.launch(server,{
|
||
|
base: troot.tmeta.tserver.tslug,
|
||
|
cors: false,
|
||
|
timeoute: 10e3
|
||
|
});
|
||
|
}
|
||
|
|
||
|
module.exports = buildCrudApi;
|