var keystone = require('keystone'),
_ = require('underscore'),
querystring = require('querystring'),
async = require('async');
exports = module.exports = function(req, res) {
var viewLocals = {
validationErrors: {},
showCreateForm: _.has(req.query, 'new')
};
var sort = { by: req.query.sort || req.list.defaultSort },
filters = req.list.processFilters(req.query.q),
cleanFilters = {},
queryFilters = req.list.getSearchFilters(req.query.search, filters),
columns = (req.query.cols) ? req.list.expandColumns(req.query.cols) : req.list.defaultColumns;
_.each(filters, function(filter, path) {
cleanFilters[path] = _.omit(filter, 'field');
});
if (sort.by) {
sort.inv = sort.by.charAt(0) === '-';
sort.path = (sort.inv) ? sort.by.substr(1) : sort.by;
sort.field = req.list.fields[sort.path];
var clearSort = function() {
delete req.query.sort;
var qs = querystring.stringify(req.query);
return res.redirect(req.path + ((qs) ? '?' + qs : ''));
};
// clear the sort query value if it is the default sort value for the list
if (req.query.sort === req.list.defaultSort) {
return clearSort();
}
if (sort.field) {
// the sort is set to a field, use its label
sort.label = sort.field.label;
// some fields have custom sort paths
if (sort.field.type === 'name') {
sort.by = sort.by + '.first ' + sort.by + '.last';
}
} else if (req.list.get('sortable') && (sort.by === 'sortOrder' || sort.by === '-sortOrder')) {
// the sort is set to the built-in sort order, set the label correctly
sort.label = 'display order';
} else if (req.query.sort) {
// it looks like an invalid path has been specified (no matching field), so clear the sort
return clearSort();
}
}
var renderView = function() {
var query = req.list.paginate({ filters: queryFilters, page: req.params.page, perPage: req.list.get('perPage') }).sort(sort.by);
req.list.selectColumns(query, columns);
var link_to = function(params) {
var p = params.page || '';
delete params.page;
var queryParams = _.clone(req.query);
for (var i in params) {
if (params[i] === undefined) {
delete params[i];
delete queryParams[i];
}
}
params = querystring.stringify(_.defaults(params, queryParams));
return keystone.get('backend dir') + '/' + req.list.path + (p ? '/' + p : '') + (params ? '?' + params : '');
};
query.exec(function(err, items) {
if (err) {
console.log(err);
return res.status(500).send('Error querying items:
' + JSON.stringify(err));
}
// if there were results but not on this page, reset the page
if (req.params.page && items.total && !items.results.length) {
return res.redirect(keystone.get('backend dir') + '/' + req.list.path);
}
// go straight to the result if there was a search, and only one result
if (req.query.search && items.total === 1 && items.results.length === 1) {
return res.redirect(keystone.get('backend dir') + '/' + req.list.path + '/' + items.results[0].id);
}
var download_link = keystone.get('backend dir') + '/' + 'download/' + req.list.path,
downloadParams = {};
if (req.query.q) {
downloadParams.q = req.query.q;
}
if (req.query.search) {
downloadParams.search = req.query.search;
}
if (req.query.cols) {
downloadParams.cols = req.query.cols;
}
downloadParams = querystring.stringify(downloadParams);
if (downloadParams) {
download_link += '?' + downloadParams;
}
var compileFields = function(item, callback) { item.compile('initial', callback); };
async.eachSeries(req.list.initialFields, compileFields , function() {
keystone.render(req, res, 'list', _.extend(viewLocals, {
section: keystone.nav.by.list[req.list.key] || {},
title: 'Keystone: ' + req.list.plural,
page: 'list',
link_to: link_to,
download_link: download_link,
list: req.list,
sort: sort,
filters: cleanFilters,
search: req.query.search,
columns: columns,
colPaths: _.pluck(columns, 'path'),
items: items,
submitted: req.body || {},
query: req.query
}));
});
});
};
var checkCSRF = function() {
var pass = keystone.security.csrf.validate(req);
if (!pass) {
req.flash('error', 'There was a problem with your request, please try again.');
}
return pass;
};
var item;
if ('update' in req.query) {
if (!checkCSRF()) return renderView();
(function() {
var data = null;
if (req.query.update) {
try {
data = JSON.parse(req.query.update);
} catch(e) {
req.flash('error', 'There was an error parsing the update data.');
return renderView();
}
}
req.list.updateAll(data, function(err) {
if (err) {
console.log('Error updating all ' + req.list.plural);
console.log(err);
req.flash('error', 'There was an error updating all ' + req.list.plural + ' (logged to console)');
} else {
req.flash('success', 'All ' + req.list.plural + ' updated successfully.');
}
res.redirect(keystone.get('backend dir') + '/' + req.list.path);
});
})();
} else if (!req.list.get('nodelete') && req.query['delete']) {
if (!checkCSRF()) return renderView();
if (req.query['delete'] === req.user.id) {
req.flash('error', 'You can\'t delete your own ' + req.list.singular + '.');
return renderView();
}
req.list.model.findById(req.query['delete']).exec(function (err, item) {
if (err || !item) return res.redirect(keystone.get('backend dir') + '/' + req.list.path);
item.remove(function (err) {
if (err) {
console.log('Error deleting ' + req.list.singular);
console.log(err);
req.flash('error', 'Error deleting the ' + req.list.singular + ': ' + err.message);
} else {
req.flash('success', req.list.singular + ' deleted successfully.');
}
res.redirect(keystone.get('backend dir') + '/' + req.list.path);
});
});
return;
} else if (!req.list.get('nocreate') && req.list.get('autocreate') && _.has(req.query, 'new')) {
if (!checkCSRF()) return renderView();
item = new req.list.model();
item.save(function(err) {
if (err) {
console.log('There was an error creating the new ' + req.list.singular + ':');
console.log(err);
req.flash('error', 'There was an error creating the new ' + req.list.singular + '.');
renderView();
} else {
req.flash('success', 'New ' + req.list.singular + ' ' + req.list.getDocumentName(item) + ' created.');
return res.redirect(keystone.get('backend dir') + '/' + req.list.path + '/' + item.id);
}
});
} else if (!req.list.get('nocreate') && req.method === 'POST' && req.body.action === 'create') {
if (!checkCSRF()) return renderView();
item = new req.list.model();
var updateHandler = item.getUpdateHandler(req);
viewLocals.showCreateForm = true; // always show the create form after a create. success will redirect.
if (req.list.nameIsInitial) {
if (!req.list.nameField.validateInput(req.body, true, item)) {
updateHandler.addValidationError(req.list.nameField.path, req.list.nameField.label + ' is required.');
}
req.list.nameField.updateItem(item, req.body);
}
updateHandler.process(req.body, {
flashErrors: true,
logErrors: true,
fields: req.list.initialFields
}, function(err) {
if (err) {
return renderView();
}
req.flash('success', 'New ' + req.list.singular + ' ' + req.list.getDocumentName(item) + ' created.');
return res.redirect(keystone.get('backend dir') + '/' + req.list.path + '/' + item.id);
});
} else {
renderView();
}
};