diff --git a/lib/models/campaigns.js b/lib/models/campaigns.js
index 1bcabcc8..5c53f2e5 100644
--- a/lib/models/campaigns.js
+++ b/lib/models/campaigns.js
@@ -19,7 +19,7 @@ let tableHelpers = require('../table-helpers');
let allowedKeys = ['description', 'from', 'address', 'reply_to', 'subject', 'editor_name', 'editor_data', 'template', 'source_url', 'list', 'segment', 'html', 'text', 'tracking_disabled'];
module.exports.list = (start, limit, callback) => {
- tableHelpers.list('campaigns', 'scheduled', start, limit, callback);
+ tableHelpers.list('campaigns', ['*'], 'scheduled', start, limit, callback);
};
module.exports.filter = (request, parent, callback) => {
@@ -38,7 +38,7 @@ module.exports.filter = (request, parent, callback) => {
};
}
- tableHelpers.filter('campaigns', request, ['#', 'name', 'description', 'status', 'created'], ['name'], 'created DESC', queryData, callback);
+ tableHelpers.filter('campaigns', ['*'], request, ['#', 'name', 'description', 'status', 'created'], ['name'], 'created DESC', queryData, callback);
};
module.exports.filterClickedSubscribers = (campaign, linkId, request, columns, callback) => {
@@ -47,7 +47,7 @@ module.exports.filterClickedSubscribers = (campaign, linkId, request, columns, c
values: [campaign.list, linkId]
};
- tableHelpers.filter('subscription__' + campaign.list + ' JOIN campaign_tracker__' + campaign.id + ' ON campaign_tracker__' + campaign.id + '.subscriber=subscription__' + campaign.list + '.id', request, columns, ['email', 'first_name', 'last_name'], 'email ASC', queryData, callback);
+ tableHelpers.filter('subscription__' + campaign.list + ' JOIN campaign_tracker__' + campaign.id + ' ON campaign_tracker__' + campaign.id + '.subscriber=subscription__' + campaign.list + '.id', ['*'], request, columns, ['email', 'first_name', 'last_name'], 'email ASC', queryData, callback);
};
module.exports.statsClickedSubscribersByColumn = (campaign, linkId, request, column, limit, callback) => {
@@ -92,7 +92,7 @@ module.exports.filterStatusSubscribers = (campaign, status, request, columns, ca
values: [campaign.list, campaign.segment && campaign.segment.id || 0, status]
};
- tableHelpers.filter('subscription__' + campaign.list + ' JOIN campaign__' + campaign.id + ' ON campaign__' + campaign.id + '.subscription=subscription__' + campaign.list + '.id', request, columns, ['email', 'first_name', 'last_name'], 'email ASC', queryData, callback);
+ tableHelpers.filter('subscription__' + campaign.list + ' JOIN campaign__' + campaign.id + ' ON campaign__' + campaign.id + '.subscription=subscription__' + campaign.list + '.id', ['*'], request, columns, ['email', 'first_name', 'last_name'], 'email ASC', queryData, callback);
};
module.exports.getByCid = (cid, callback) => {
diff --git a/lib/models/lists.js b/lib/models/lists.js
index feaadd08..dc1a0912 100644
--- a/lib/models/lists.js
+++ b/lib/models/lists.js
@@ -10,7 +10,11 @@ let tableHelpers = require('../table-helpers');
let allowedKeys = ['description', 'default_form', 'public_subscribe'];
module.exports.list = (start, limit, callback) => {
- tableHelpers.list('lists', 'name', start, limit, callback);
+ tableHelpers.list('lists', ['*'], 'name', start, limit, callback);
+};
+
+module.exports.filter = (request, parent, callback) => {
+ tableHelpers.filter('lists', ['*'], request, ['#', 'name', 'cid', 'subscribers', 'description'], ['name'], 'name ASC', null, callback);
};
module.exports.quicklist = callback => {
diff --git a/lib/models/subscriptions.js b/lib/models/subscriptions.js
index 7d0b83ee..f5fb5f84 100644
--- a/lib/models/subscriptions.js
+++ b/lib/models/subscriptions.js
@@ -21,7 +21,7 @@ module.exports.list = (listId, start, limit, callback) => {
return callback(new Error('Missing List ID'));
}
- tableHelpers.list('subscription__' + listId, 'email', start, limit, (err, rows, total) => {
+ tableHelpers.list('subscription__' + listId, ['*'], 'email', start, limit, (err, rows, total) => {
if (!err) {
rows = rows.map(row => tools.convertKeys(row));
}
@@ -80,10 +80,10 @@ module.exports.filter = (listId, request, columns, segmentId, callback) => {
return callback(err);
}
- tableHelpers.filter('subscription__' + listId, request, columns, ['email', 'first_name', 'last_name'], 'email ASC', queryData, callback);
+ tableHelpers.filter('subscription__' + listId, ['*'], request, columns, ['email', 'first_name', 'last_name'], 'email ASC', queryData, callback);
});
} else {
- tableHelpers.filter('subscription__' + listId, request, columns, ['email', 'first_name', 'last_name'], 'email ASC', null, callback);
+ tableHelpers.filter('subscription__' + listId, ['*'], request, columns, ['email', 'first_name', 'last_name'], 'email ASC', null, callback);
}
};
diff --git a/lib/models/templates.js b/lib/models/templates.js
index 48fde524..09f0abb3 100644
--- a/lib/models/templates.js
+++ b/lib/models/templates.js
@@ -8,23 +8,15 @@ let tableHelpers = require('../table-helpers');
let allowedKeys = ['description', 'editor_name', 'editor_data', 'html', 'text'];
module.exports.list = (start, limit, callback) => {
- tableHelpers.list('templates', 'name', start, limit, callback);
+ tableHelpers.list('templates', ['*'], 'name', start, limit, callback);
+};
+
+module.exports.filter = (request, parent, callback) => {
+ tableHelpers.filter('templates', ['*'], request, ['#', 'name', 'description'], ['name'], 'name ASC', null, callback);
};
module.exports.quicklist = callback => {
- db.getConnection((err, connection) => {
- if (err) {
- return callback(err);
- }
-
- connection.query('SELECT id, name FROM templates ORDER BY name LIMIT 1000', (err, rows) => {
- connection.release();
- if (err) {
- return callback(err);
- }
- return callback(null, (rows || []).map(tools.convertKeys));
- });
- });
+ tableHelpers.quicklist('templates', ['id', 'name'], 'name', callback);
};
module.exports.get = (id, callback) => {
diff --git a/lib/models/triggers.js b/lib/models/triggers.js
index a3658240..35e424d3 100644
--- a/lib/models/triggers.js
+++ b/lib/models/triggers.js
@@ -345,7 +345,7 @@ module.exports.filterSubscribers = (trigger, request, columns, callback) => {
values: [trigger.list]
};
- tableHelpers.filter('subscription__' + trigger.list + ' JOIN trigger__' + trigger.id + ' ON trigger__' + trigger.id + '.subscription=subscription__' + trigger.list + '.id', request, columns, ['email', 'first_name', 'last_name'], 'email ASC', queryData, callback);
+ tableHelpers.filter('subscription__' + trigger.list + ' JOIN trigger__' + trigger.id + ' ON trigger__' + trigger.id + '.subscription=subscription__' + trigger.list + '.id', ['*'], request, columns, ['email', 'first_name', 'last_name'], 'email ASC', queryData, callback);
};
function createTriggerTable(id, callback) {
diff --git a/lib/table-helpers.js b/lib/table-helpers.js
index 245e54b1..3ab373cc 100644
--- a/lib/table-helpers.js
+++ b/lib/table-helpers.js
@@ -4,13 +4,13 @@ let db = require('./db');
let tools = require('./tools');
let log = require('npmlog');
-module.exports.list = (source, orderBy, start, limit, callback) => {
+module.exports.list = (source, fields, orderBy, start, limit, callback) => {
db.getConnection((err, connection) => {
if (err) {
return callback(err);
}
- connection.query('SELECT SQL_CALC_FOUND_ROWS * FROM ' + source + ' ORDER BY ' + orderBy + ' DESC LIMIT ? OFFSET ?', [limit, start], (err, rows) => {
+ connection.query('SELECT SQL_CALC_FOUND_ROWS ' + fields.join(', ') + ' FROM ' + source + ' ORDER BY ' + orderBy + ' DESC LIMIT ? OFFSET ?', [limit, start], (err, rows) => {
if (err) {
connection.release();
return callback(err);
@@ -26,8 +26,23 @@ module.exports.list = (source, orderBy, start, limit, callback) => {
});
};
+module.exports.quicklist = (source, fields, orderBy, callback) => {
+ db.getConnection((err, connection) => {
+ if (err) {
+ return callback(err);
+ }
-module.exports.filter = (source, request, columns, searchFields, defaultOrdering, queryData, callback) => {
+ connection.query('SELECT ' + fields.join(', ') + ' FROM ' + source + ' ORDER BY ' + orderBy + ' LIMIT 1000', (err, rows) => {
+ connection.release();
+ if (err) {
+ return callback(err);
+ }
+ return callback(null, (rows || []).map(tools.convertKeys));
+ });
+ });
+};
+
+module.exports.filter = (source, fields, request, columns, searchFields, defaultOrdering, queryData, callback) => {
db.getConnection((err, connection) => {
if (err) {
return callback(err);
@@ -41,6 +56,8 @@ module.exports.filter = (source, request, columns, searchFields, defaultOrdering
values = values.concat(queryData.values || []);
}
+ log.info("tableHelpers", query);
+
connection.query(query, values, (err, total) => {
if (err) {
connection.release();
@@ -56,7 +73,7 @@ module.exports.filter = (source, request, columns, searchFields, defaultOrdering
let orderField = columns[Number(order.column)];
let orderDirection = (order.dir || '').toString().toLowerCase() === 'desc' ? 'DESC' : 'ASC';
if (orderField) {
- ordering.push('`' + orderField + '` ' + orderDirection);
+ ordering.push(orderField + ' ' + orderDirection);
}
});
}
@@ -75,9 +92,11 @@ module.exports.filter = (source, request, columns, searchFields, defaultOrdering
searchArgs = searchFields.map(field => searchVal)
}
- let query = 'SELECT SQL_CALC_FOUND_ROWS * FROM ' + source +' WHERE ' + (searchWhere ? '(' + searchWhere + ')': '1') + (queryData ? ' AND (' + queryData.where + ')' : '') + ' ORDER BY ' + ordering.join(', ') + ' LIMIT ? OFFSET ?';
+ let query = 'SELECT SQL_CALC_FOUND_ROWS ' + fields.join(', ') + ' FROM ' + source +' WHERE ' + (searchWhere ? '(' + searchWhere + ')': '1') + (queryData ? ' AND (' + queryData.where + ')' : '') + ' ORDER BY ' + ordering.join(', ') + ' LIMIT ? OFFSET ?';
let args = searchArgs.concat(queryData ? queryData.values : []).concat([Number(request.length) || 50, Number(request.start) || 0]);
+ log.info("tableHelpers", query);
+
connection.query(query, args, (err, rows) => {
if (err) {
connection.release();
diff --git a/public/javascript/tables.js b/public/javascript/tables.js
index 7faad36b..5ed32987 100644
--- a/public/javascript/tables.js
+++ b/public/javascript/tables.js
@@ -4,73 +4,72 @@
'use strict';
-$('.data-table').each(function () {
- var rowSort = $(this).data('rowSort') || false;
- var columns = false;
+(function(){
+ function getDataTableOptions(elem) {
+ var rowSort = $(elem).data('rowSort') || false;
- if (rowSort) {
- columns = rowSort.split(',').map(function (sort) {
- return {
- orderable: sort === '1'
- };
- });
+ var columns = false;
+
+ var sortColumn = $(elem).data('sortColumn') === undefined ? 1 : Number($(elem).data('sortColumn'));
+ var sortOrder = ($(elem).data('sortOrder') || 'asc').toString().trim().toLowerCase();
+
+ var paging = $(elem).data('paging') === false ? false : true;
+
+ // allow only asc and desc
+ if (sortOrder !== 'desc') {
+ sortOrder = 'asc';
+ }
+
+ var columnsCount = 0;
+ var columnsSort = []
+
+ if (rowSort) {
+ columns = rowSort.split(',').map(function (sort) {
+ return {
+ orderable: sort === '1'
+ };
+ });
+ }
+
+ return {
+ scrollX: true,
+ order: [
+ [sortColumn, sortOrder]
+ ],
+ columns: columns,
+ paging: paging,
+ info: paging, /* This controls the "Showing 1 to 16 of 16 entries" */
+ pageLength: 50
+ };
}
- $(this).DataTable({
- scrollX: true,
- order: [
- [1, 'asc']
- ],
- columns: columns,
- pageLength: 50
+ $('.data-table').each(function () {
+ var opts = getDataTableOptions(this);
+ $(this).DataTable(opts);
});
-});
-$('.data-table-ajax').each(function () {
- var rowSort = $(this).data('rowSort') || false;
- var columns = false;
+ $('.data-table-ajax').each(function () {
+ var topicUrl = $(this).data('topicUrl') || '/lists';
+ var topicArgs = $(this).data('topicArgs') || false;
+ var topicId = $(this).data('topicId') || '';
- var topicUrl = $(this).data('topicUrl') || '/lists';
- var topicArgs = $(this).data('topicArgs') || false;
- var topicId = $(this).data('topicId') || '';
+ var ajaxUrl = topicUrl + '/ajax/' + topicId + (topicArgs ? '?' + topicArgs : '');
- var sortColumn = Number($(this).data('sortColumn')) || 1;
- var sortOrder = ($(this).data('sortOrder') || 'asc').toString().trim().toLowerCase();
-
- // allow only asc and desc
- if (sortOrder !== 'desc') {
- sortOrder = 'asc';
- }
-
- var ajaxUrl = topicUrl + '/ajax/' + topicId + (topicArgs ? '?' + topicArgs : '');
-
- if (rowSort) {
- columns = rowSort.split(',').map(function (sort) {
- return {
- orderable: sort === '1'
- };
- });
- }
-
- $(this).DataTable({
- scrollX: true,
- serverSide: true,
- ajax: {
+ var opts = getDataTableOptions(this);
+ opts.ajax = {
url: ajaxUrl,
type: 'POST'
- },
- order: [
- [sortColumn, sortOrder]
- ],
- columns: columns,
- pageLength: 50,
- processing: true
- }).on('draw', function () {
- $('.datestring').each(function () {
- $(this).html(moment($(this).data('date')).fromNow());
+ };
+ opts.serverSide = true;
+ opts.processing = true;
+
+ $(this).DataTable(opts).on('draw', function () {
+ $('.datestring').each(function () {
+ $(this).html(moment($(this).data('date')).fromNow());
+ });
});
});
-});
+})();
$('.data-stats-pie-chart').each(function () {
var column = $(this).data('column') || 'country';
diff --git a/routes/campaigns.js b/routes/campaigns.js
index 08b3e230..18c15de9 100644
--- a/routes/campaigns.js
+++ b/routes/campaigns.js
@@ -673,6 +673,80 @@ router.post('/status/ajax/:id/:status', (req, res) => {
});
});
+router.post('/clicked/ajax/:id/:linkId', (req, res) => {
+ let linkId = Number(req.params.linkId) || 0;
+
+ campaigns.get(req.params.id, true, (err, campaign) => {
+ if (err || !campaign) {
+ return res.json({
+ error: err && err.message || err || _('Campaign not found'),
+ data: []
+ });
+ }
+ lists.get(campaign.list, (err, list) => {
+ if (err) {
+ return res.json({
+ error: err && err.message || err,
+ data: []
+ });
+ }
+
+ let campaignCid = campaign.cid;
+ let listCid = list.cid;
+
+ let columns = ['#', 'email', 'first_name', 'last_name', 'campaign_tracker__' + campaign.id + '`.`created', 'count'];
+ campaigns.filterClickedSubscribers(campaign, linkId, req.body, columns, (err, data, total, filteredTotal) => {
+ if (err) {
+ return res.json({
+ error: err.message || err,
+ data: []
+ });
+ }
+
+ res.json({
+ draw: req.body.draw,
+ recordsTotal: total,
+ recordsFiltered: filteredTotal,
+ data: data.map((row, i) => [
+ '' + ((Number(req.body.start) || 0) + 1 + i) + '',
+ htmlescape(row.email || ''),
+ htmlescape(row.firstName || ''),
+ htmlescape(row.lastName || ''),
+ row.created && row.created.toISOString ? '' + row.created.toISOString() + '' : 'N/A',
+ row.count,
+ '' + _('Edit') + ''
+ ])
+ });
+ });
+ });
+ });
+});
+
+router.post('/selection/ajax', (req, res) => {
+ campaigns.filter(req.body, Number(req.query.parent) || false, (err, data, total, filteredTotal) => {
+ if (err) {
+ return res.json({
+ error: err.message || err,
+ data: []
+ });
+ }
+
+ res.json({
+ draw: req.body.draw,
+ recordsTotal: total,
+ recordsFiltered: filteredTotal,
+ data: data.map((row, i) => [
+ '',
+ (Number(req.body.start) || 0) + 1 + i,
+ ' ' + htmlescape(row.name || '') + '',
+ htmlescape(striptags(row.description) || ''),
+ '' + row.created.toISOString() + '']
+ )
+ });
+ });
+});
+
+
router.post('/delete', passport.parseForm, passport.csrfProtection, (req, res) => {
campaigns.delete(req.body.id, (err, deleted) => {
if (err) {
diff --git a/routes/lists.js b/routes/lists.js
index 198fb7df..1ae18d7c 100644
--- a/routes/lists.js
+++ b/routes/lists.js
@@ -55,23 +55,8 @@ router.all('/*', (req, res, next) => {
});
router.get('/', (req, res) => {
- let limit = 999999999;
- let start = 0;
-
- lists.list(start, limit, (err, rows, total) => {
- if (err) {
- req.flash('danger', err.message || err);
- return res.redirect('/');
- }
-
- res.render('lists/lists', {
- rows: rows.map((row, i) => {
- row.index = start + i + 1;
- row.description = striptags(row.description);
- return row;
- }),
- total
- });
+ res.render('lists/lists', {
+ title: _('Lists')
});
});
@@ -159,6 +144,32 @@ router.post('/delete', passport.parseForm, passport.csrfProtection, (req, res) =
});
});
+router.post('/ajax', (req, res) => {
+ lists.filter(req.body, Number(req.query.parent) || false, (err, data, total, filteredTotal) => {
+ if (err) {
+ return res.json({
+ error: err.message || err,
+ data: []
+ });
+ }
+
+ res.json({
+ draw: req.body.draw,
+ recordsTotal: total,
+ recordsFiltered: filteredTotal,
+ data: data.map((row, i) => [
+ (Number(req.body.start) || 0) + 1 + i,
+ ' ' + htmlescape(row.name || '') + '',
+ '' + row.cid + '
',
+ row.subscribers,
+ htmlescape(striptags(row.description) || ''),
+ '' + _('Edit') + '' ]
+ )
+ });
+ });
+});
+
+
router.post('/ajax/:id', (req, res) => {
lists.get(req.params.id, (err, list) => {
if (err || !list) {
diff --git a/routes/templates.js b/routes/templates.js
index 4b08ea86..3272df52 100644
--- a/routes/templates.js
+++ b/routes/templates.js
@@ -8,6 +8,7 @@ let settings = require('../lib/models/settings');
let tools = require('../lib/tools');
let helpers = require('../lib/helpers');
let striptags = require('striptags');
+let htmlescape = require('escape-html');
let passport = require('../lib/passport');
let mailer = require('../lib/mailer');
let _ = require('../lib/translate')._;
@@ -22,23 +23,8 @@ router.all('/*', (req, res, next) => {
});
router.get('/', (req, res) => {
- let limit = 999999999;
- let start = 0;
-
- templates.list(start, limit, (err, rows, total) => {
- if (err) {
- req.flash('danger', err.message || err);
- return res.redirect('/');
- }
-
- res.render('templates/templates', {
- rows: rows.map((row, i) => {
- row.index = start + i + 1;
- row.description = striptags(row.description);
- return row;
- }),
- total
- });
+ res.render('templates/templates', {
+ title: _('Templates')
});
});
@@ -164,4 +150,27 @@ router.post('/delete', passport.parseForm, passport.csrfProtection, (req, res) =
});
});
+router.post('/ajax', (req, res) => {
+ templates.filter(req.body, Number(req.query.parent) || false, (err, data, total, filteredTotal) => {
+ if (err) {
+ return res.json({
+ error: err.message || err,
+ data: []
+ });
+ }
+
+ res.json({
+ draw: req.body.draw,
+ recordsTotal: total,
+ recordsFiltered: filteredTotal,
+ data: data.map((row, i) => [
+ (Number(req.body.start) || 0) + 1 + i,
+ ' ' + htmlescape(row.name || ''),
+ htmlescape(striptags(row.description) || ''),
+ '' + _('Edit') + '' ]
+ )
+ });
+ });
+});
+
module.exports = router;
diff --git a/views/lists/lists.hbs b/views/lists/lists.hbs
index 64886833..93cc4918 100644
--- a/views/lists/lists.hbs
+++ b/views/lists/lists.hbs
@@ -12,57 +12,26 @@
- # - | -- {{#translate}}Name{{/translate}} - | -- {{#translate}}ID{{/translate}} - | -- {{#translate}}Subscribers{{/translate}} - | -- {{#translate}}Description{{/translate}} - | -- - | ++ # + | ++ {{#translate}}Name{{/translate}} + | ++ {{#translate}}ID{{/translate}} + | ++ {{#translate}}Subscribers{{/translate}} + | ++ {{#translate}}Description{{/translate}} + | ++ + | - {{#if rows}} - - {{#each rows}} -
---|---|---|---|---|---|
- {{index}} - | -- - - {{name}} - - | -
- {{cid}}
- |
- - {{subscribers}} - | -- {{description}} - | -- - {{#translate}}Edit{{/translate}} - - | -
# @@ -27,28 +27,5 @@ | - {{#if rows}} - - {{#each rows}} -|||
---|---|---|---|
- {{index}} - | -- {{name}} - | -
- {{description}} - |
- - - - {{#translate}}Edit{{/translate}} - - | -