Added the option to select lists in report.
Added an option to generate a CSV report.
This commit is contained in:
parent
6ba04d7ff4
commit
2056645023
8 changed files with 177 additions and 50 deletions
|
@ -17,6 +17,10 @@ module.exports.filter = (request, parent, callback) => {
|
||||||
tableHelpers.filter('lists', ['*'], request, ['#', 'name', 'cid', 'subscribers', 'description'], ['name'], 'name ASC', null, callback);
|
tableHelpers.filter('lists', ['*'], request, ['#', 'name', 'cid', 'subscribers', 'description'], ['name'], 'name ASC', null, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports.filterQuicklist = (request, callback) => {
|
||||||
|
tableHelpers.filter('lists', ['id', 'name', 'subscribers'], request, ['#', 'name', 'subscribers'], ['name'], 'name ASC', null, callback);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.quicklist = callback => {
|
module.exports.quicklist = callback => {
|
||||||
db.getConnection((err, connection) => {
|
db.getConnection((err, connection) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ module.exports.list = (start, limit, callback) => {
|
||||||
|
|
||||||
module.exports.filter = (request, callback) => {
|
module.exports.filter = (request, callback) => {
|
||||||
tableHelpers.filter('reports JOIN report_templates ON reports.report_template = report_templates.id',
|
tableHelpers.filter('reports JOIN report_templates ON reports.report_template = report_templates.id',
|
||||||
['reports.id AS id', 'reports.name AS name', 'reports.description AS description', 'reports.report_template AS report_template', 'reports.params AS params', 'reports.created AS created', 'report_templates.name AS report_template_name' ],
|
['reports.id AS id', 'reports.name AS name', 'reports.description AS description', 'reports.report_template AS report_template', 'reports.params AS params', 'reports.created AS created', 'report_templates.name AS report_template_name', 'report_templates.mime_type AS mime_type' ],
|
||||||
request, ['#', 'name', 'report_templates.name', 'description', 'created'], ['name'], 'created DESC', null, callback);
|
request, ['#', 'name', 'report_templates.name', 'description', 'created'], ['name'], 'created DESC', null, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,19 @@ module.exports.list = (source, fields, orderBy, start, limit, callback) => {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.query('SELECT SQL_CALC_FOUND_ROWS ' + fields.join(', ') + ' FROM ' + source + ' ORDER BY ' + orderBy + ' DESC LIMIT ? OFFSET ?', [limit, start], (err, rows) => {
|
let limitQuery = '';
|
||||||
|
let limitValues = [];
|
||||||
|
if (limit) {
|
||||||
|
limitQuery = ' LIMIT ?';
|
||||||
|
limitValues.push(limit);
|
||||||
|
|
||||||
|
if (start) {
|
||||||
|
limitQuery += ' OFFSET ?';
|
||||||
|
limitValues.push(start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.query('SELECT SQL_CALC_FOUND_ROWS ' + fields.join(', ') + ' FROM ' + source + ' ORDER BY ' + orderBy + ' DESC' + limitQuery, limitValues, (err, rows) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
connection.release();
|
connection.release();
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
@ -56,8 +68,6 @@ module.exports.filter = (source, fields, request, columns, searchFields, default
|
||||||
values = values.concat(queryData.values || []);
|
values = values.concat(queryData.values || []);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("tableHelpers", query);
|
|
||||||
|
|
||||||
connection.query(query, values, (err, total) => {
|
connection.query(query, values, (err, total) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
connection.release();
|
connection.release();
|
||||||
|
|
|
@ -748,4 +748,27 @@ router.get('/subscription/:id/import/:importId/failed', (req, res) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('/quicklist/ajax', (req, res) => {
|
||||||
|
lists.filterQuicklist(req.body, (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) => ({
|
||||||
|
"0": (Number(req.body.start) || 0) + 1 + i,
|
||||||
|
"1": '<span class="glyphicon glyphicon-inbox" aria-hidden="true"></span> <a href="/lists/view/' + row.id + '">' + htmlescape(row.name || '') + '</a>',
|
||||||
|
"2": row.subscribers,
|
||||||
|
"DT_RowId": row.id
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
@ -62,7 +62,7 @@ router.get('/create', passport.csrfProtection, (req, res) => {
|
||||||
const wizard = req.query['type'] || '';
|
const wizard = req.query['type'] || '';
|
||||||
|
|
||||||
if (wizard == 'subscribers-all') {
|
if (wizard == 'subscribers-all') {
|
||||||
if (!('description' in data)) data.description = 'This sample shows how to generate a report listing all subscribers along with their statistics.';
|
if (!('description' in data)) data.description = 'Generates a campaign report listing all subscribers along with their statistics.';
|
||||||
|
|
||||||
if (!('mimeType' in data)) data.mimeType = 'text/html';
|
if (!('mimeType' in data)) data.mimeType = 'text/html';
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ router.get('/create', passport.csrfProtection, (req, res) => {
|
||||||
'</div>';
|
'</div>';
|
||||||
|
|
||||||
} else if (wizard == 'subscribers-grouped') {
|
} else if (wizard == 'subscribers-grouped') {
|
||||||
if (!('description' in data)) data.description = 'This sample shows how to generate a report where results are aggregated by some (typically custom) field. The sample assumes that the list associated with the campaign contains a custom field "Country" (which would be filled in via the subscription form).';
|
if (!('description' in data)) data.description = 'Generates a campaign report with results are aggregated by some "Country" custom field.';
|
||||||
|
|
||||||
if (!('mimeType' in data)) data.mimeType = 'text/html';
|
if (!('mimeType' in data)) data.mimeType = 'text/html';
|
||||||
|
|
||||||
|
@ -142,13 +142,13 @@ router.get('/create', passport.csrfProtection, (req, res) => {
|
||||||
if (!('js' in data)) data.js =
|
if (!('js' in data)) data.js =
|
||||||
'const reports = require("../lib/models/reports");\n' +
|
'const reports = require("../lib/models/reports");\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'reports.getCampaignResults(inputs.campaign, ["custom_country", "count(*) AS countAll", "SUM(IF(tracker.count IS NULL, 0, 1)) AS countOpened"], "GROUP BY custom_country", (err, results) => {\n' +
|
'reports.getCampaignResults(inputs.campaign, ["custom_country", "count(*) AS count_all", "SUM(IF(tracker.count IS NULL, 0, 1)) AS count_opened"], "GROUP BY custom_country", (err, results) => {\n' +
|
||||||
' if (err) {\n' +
|
' if (err) {\n' +
|
||||||
' return callback(err);\n' +
|
' return callback(err);\n' +
|
||||||
' }\n' +
|
' }\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
' for (let row of results) {\n' +
|
' for (let row of results) {\n' +
|
||||||
' row["percentage"] = Math.round((row.countOpened / row.countAll) * 100);\n' +
|
' row["percentage"] = Math.round((row.count_opened / row.count_all) * 100);\n' +
|
||||||
' }\n' +
|
' }\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
' let data = {\n' +
|
' let data = {\n' +
|
||||||
|
@ -186,10 +186,10 @@ router.get('/create', passport.csrfProtection, (req, res) => {
|
||||||
' {{custom_zone}}\n' +
|
' {{custom_zone}}\n' +
|
||||||
' </th>\n' +
|
' </th>\n' +
|
||||||
' <td style="width: 20%;">\n' +
|
' <td style="width: 20%;">\n' +
|
||||||
' {{countOpened}}\n' +
|
' {{count_opened}}\n' +
|
||||||
' </td>\n' +
|
' </td>\n' +
|
||||||
' <td style="width: 20%;">\n' +
|
' <td style="width: 20%;">\n' +
|
||||||
' {{countAll}}\n' +
|
' {{count_all}}\n' +
|
||||||
' </td>\n' +
|
' </td>\n' +
|
||||||
' <td style="width: 20%;">\n' +
|
' <td style="width: 20%;">\n' +
|
||||||
' {{percentage}}%\n' +
|
' {{percentage}}%\n' +
|
||||||
|
@ -200,6 +200,43 @@ router.get('/create', passport.csrfProtection, (req, res) => {
|
||||||
' {{/if}}\n' +
|
' {{/if}}\n' +
|
||||||
' </table>\n' +
|
' </table>\n' +
|
||||||
'</div>';
|
'</div>';
|
||||||
|
|
||||||
|
} else if (wizard == 'export-list-csv') {
|
||||||
|
if (!('description' in data)) data.description = 'Exports a list as a CSV file.';
|
||||||
|
|
||||||
|
if (!('mimeType' in data)) data.mimeType = 'text/csv';
|
||||||
|
|
||||||
|
if (!('userFields' in data)) data.userFields =
|
||||||
|
'[\n' +
|
||||||
|
' {\n' +
|
||||||
|
' "id": "list",\n' +
|
||||||
|
' "name": "List",\n' +
|
||||||
|
' "type": "list",\n' +
|
||||||
|
' "minOccurences": 1,\n' +
|
||||||
|
' "maxOccurences": 1\n' +
|
||||||
|
' }\n' +
|
||||||
|
']';
|
||||||
|
|
||||||
|
if (!('js' in data)) data.js =
|
||||||
|
'const subscriptions = require("../lib/models/subscriptions");\n' +
|
||||||
|
'\n' +
|
||||||
|
'subscriptions.list(inputs.list.id,0,0, (err, results) => {\n' +
|
||||||
|
' if (err) {\n' +
|
||||||
|
' return callback(err);\n' +
|
||||||
|
' }\n' +
|
||||||
|
'\n' +
|
||||||
|
' let data = {\n' +
|
||||||
|
' title: "Sample Export of " + inputs.list.name,\n' +
|
||||||
|
' results: results\n' +
|
||||||
|
' };\n' +
|
||||||
|
'\n' +
|
||||||
|
' return callback(null, data);\n' +
|
||||||
|
'});';
|
||||||
|
|
||||||
|
if (!('hbs' in data)) data.hbs =
|
||||||
|
'{{#each results}}\n' +
|
||||||
|
'{{firstName}},{{lastName}},{{email}}\n' +
|
||||||
|
'{{/each}}';
|
||||||
}
|
}
|
||||||
|
|
||||||
data.csrfToken = req.csrfToken();
|
data.csrfToken = req.csrfToken();
|
||||||
|
|
|
@ -7,6 +7,7 @@ const _ = require('../lib/translate')._;
|
||||||
const reportTemplates = require('../lib/models/report-templates');
|
const reportTemplates = require('../lib/models/report-templates');
|
||||||
const reports = require('../lib/models/reports');
|
const reports = require('../lib/models/reports');
|
||||||
const campaigns = require('../lib/models/campaigns');
|
const campaigns = require('../lib/models/campaigns');
|
||||||
|
const lists = require('../lib/models/lists');
|
||||||
const tools = require('../lib/tools');
|
const tools = require('../lib/tools');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
const htmlescape = require('escape-html');
|
const htmlescape = require('escape-html');
|
||||||
|
@ -30,6 +31,12 @@ router.get('/', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/ajax', (req, res) => {
|
router.post('/ajax', (req, res) => {
|
||||||
|
function getViewIcon(mimeType) {
|
||||||
|
let icon = 'search';
|
||||||
|
if (mimeType == 'text/csv') icon = 'download-alt';
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
reports.filter(req.body, (err, data, total, filteredTotal) => {
|
reports.filter(req.body, (err, data, total, filteredTotal) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.json({
|
return res.json({
|
||||||
|
@ -48,7 +55,7 @@ router.post('/ajax', (req, res) => {
|
||||||
htmlescape(row.reportTemplateName || ''),
|
htmlescape(row.reportTemplateName || ''),
|
||||||
htmlescape(striptags(row.description) || ''),
|
htmlescape(striptags(row.description) || ''),
|
||||||
'<span class="datestring" data-date="' + row.created.toISOString() + '" title="' + row.created.toISOString() + '">' + row.created.toISOString() + '</span>',
|
'<span class="datestring" data-date="' + row.created.toISOString() + '" title="' + row.created.toISOString() + '">' + row.created.toISOString() + '</span>',
|
||||||
'<a href="/reports/view/' + row.id + '"><span class="glyphicon glyphicon-search" aria-hidden="true"></span></a> ' +
|
'<a href="/reports/view/' + row.id + '"><span class="glyphicon glyphicon-' + getViewIcon(row.mimeType) + '" aria-hidden="true"></span></a> ' +
|
||||||
'<a href="/reports/edit/' + row.id + '"><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span></a>']
|
'<a href="/reports/edit/' + row.id + '"><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span></a>']
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -123,15 +130,15 @@ router.get('/edit/:id', passport.csrfProtection, (req, res) => {
|
||||||
skip: ['layout']
|
skip: ['layout']
|
||||||
});
|
});
|
||||||
|
|
||||||
reports.get(req.params.id, (err, template) => {
|
reports.get(req.params.id, (err, report) => {
|
||||||
if (err || !template) {
|
if (err || !report) {
|
||||||
req.flash('danger', err && err.message || err || _('Could not find report with specified ID'));
|
req.flash('danger', err && err.message || err || _('Could not find report with specified ID'));
|
||||||
return res.redirect('/reports');
|
return res.redirect('/reports');
|
||||||
}
|
}
|
||||||
|
|
||||||
template.csrfToken = req.csrfToken();
|
report.csrfToken = req.csrfToken();
|
||||||
template.title = _('Edit Report');
|
report.title = _('Edit Report');
|
||||||
template.useEditor = true;
|
report.useEditor = true;
|
||||||
|
|
||||||
reportTemplates.quicklist((err, items) => {
|
reportTemplates.quicklist((err, items) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -139,7 +146,7 @@ router.get('/edit/:id', passport.csrfProtection, (req, res) => {
|
||||||
return res.redirect('/');
|
return res.redirect('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
const reportTemplateId = template.reportTemplate;
|
const reportTemplateId = report.reportTemplate;
|
||||||
|
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
if (item.id === reportTemplateId) {
|
if (item.id === reportTemplateId) {
|
||||||
|
@ -147,9 +154,9 @@ router.get('/edit/:id', passport.csrfProtection, (req, res) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
template.reportTemplates = items;
|
report.reportTemplates = items;
|
||||||
|
|
||||||
addUserFields(reportTemplateId, reqData, template, (err, data) => {
|
addUserFields(reportTemplateId, reqData, report, (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
req.flash('danger', err.message || err);
|
req.flash('danger', err.message || err);
|
||||||
return res.redirect('/reports');
|
return res.redirect('/reports');
|
||||||
|
@ -201,18 +208,18 @@ router.post('/delete', passport.parseForm, passport.csrfProtection, (req, res) =
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/view/:id', passport.csrfProtection, (req, res) => {
|
router.get('/view/:id', passport.csrfProtection, (req, res) => {
|
||||||
reports.get(req.params.id, (err, template) => {
|
reports.get(req.params.id, (err, report) => {
|
||||||
if (err || !template) {
|
if (err || !report) {
|
||||||
req.flash('danger', err && err.message || err || _('Could not find report with specified ID'));
|
req.flash('danger', err && err.message || err || _('Could not find report with specified ID'));
|
||||||
return res.redirect('/reports');
|
return res.redirect('/reports');
|
||||||
}
|
}
|
||||||
|
|
||||||
reportTemplates.get(template.reportTemplate, (err, reportTemplate) => {
|
reportTemplates.get(report.reportTemplate, (err, reportTemplate) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveUserFields(reportTemplate.userFieldsObject, template.paramsObject, (err, inputs) => {
|
resolveUserFields(reportTemplate.userFieldsObject, report.paramsObject, (err, inputs) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
req.flash('danger', err.message || err);
|
req.flash('danger', err.message || err);
|
||||||
return res.redirect('/reports');
|
return res.redirect('/reports');
|
||||||
|
@ -228,31 +235,45 @@ router.get('/view/:id', passport.csrfProtection, (req, res) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const hbsTmpl = hbs.handlebars.compile(reportTemplate.hbs);
|
const hbsTmpl = hbs.handlebars.compile(reportTemplate.hbs);
|
||||||
const report = hbsTmpl(outputs);
|
const reportText = hbsTmpl(outputs);
|
||||||
|
|
||||||
const data = {
|
if (reportTemplate.mimeType == 'text/html') {
|
||||||
csrfToken: req.csrfToken(),
|
const data = {
|
||||||
report: new hbs.handlebars.SafeString(report),
|
csrfToken: req.csrfToken(),
|
||||||
title: outputs.title
|
report: new hbs.handlebars.SafeString(reportText),
|
||||||
};
|
title: outputs.title
|
||||||
|
};
|
||||||
|
|
||||||
res.render('reports/view', data);
|
res.render('reports/view', data);
|
||||||
|
|
||||||
|
} else if (reportTemplate.mimeType == 'text/csv') {
|
||||||
|
res.set('Content-Disposition', 'attachment;filename=' + toFileName(report.name) + '.csv');
|
||||||
|
res.set('Content-Type', 'text/csv');
|
||||||
|
res.send(new Buffer(reportText));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
req.flash('danger', _('Unknown type of template'));
|
||||||
|
return res.redirect('/reports');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
const script = new vm.Script(reportTemplate.js);
|
||||||
const script = new vm.Script(reportTemplate.js);
|
script.runInNewContext(sandbox, { displayErrors: true, timeout: 10000 });
|
||||||
script.runInNewContext(sandbox, { displayErrors: true, timeout: 10000 });
|
|
||||||
} catch (err) {
|
|
||||||
req.flash('danger', 'Error in the report template script ... ' + err.stack.replace(/at ContextifyScript.Script.runInContext[\s\S]*/,''));
|
|
||||||
return res.redirect('/reports');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function resolveCampaigns(ids, callback) {
|
function toFileName(name) {
|
||||||
|
return name.
|
||||||
|
trim().
|
||||||
|
toLowerCase().
|
||||||
|
replace(/[ .+/]/g, '-').
|
||||||
|
replace(/[^a-z0-9\-_]/gi, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveEntities(getter, ids, callback) {
|
||||||
const idsRemaining = ids.slice();
|
const idsRemaining = ids.slice();
|
||||||
const resolved = [];
|
const resolved = [];
|
||||||
|
|
||||||
|
@ -261,12 +282,12 @@ function resolveCampaigns(ids, callback) {
|
||||||
return callback(null, resolved);
|
return callback(null, resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
campaigns.get(idsRemaining.shift(), false, (err, campaign) => {
|
getter(idsRemaining.shift(), (err, entity) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolved.push(campaign);
|
resolved.push(entity);
|
||||||
return doWork();
|
return doWork();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -274,6 +295,11 @@ function resolveCampaigns(ids, callback) {
|
||||||
setImmediate(doWork);
|
setImmediate(doWork);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userFieldTypeToGetter = {
|
||||||
|
'campaign': (id, callback) => campaigns.get(id, false, callback),
|
||||||
|
'list': lists.get
|
||||||
|
};
|
||||||
|
|
||||||
function resolveUserFields(userFields, params, callback) {
|
function resolveUserFields(userFields, params, callback) {
|
||||||
const userFieldsRemaining = userFields.slice();
|
const userFieldsRemaining = userFields.slice();
|
||||||
const resolved = {};
|
const resolved = {};
|
||||||
|
@ -284,25 +310,27 @@ function resolveUserFields(userFields, params, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const spec = userFieldsRemaining.shift();
|
const spec = userFieldsRemaining.shift();
|
||||||
if (spec.type == 'campaign') {
|
const getter = userFieldTypeToGetter[spec.type];
|
||||||
return resolveCampaigns(params[spec.id], (err, campaigns) => {
|
|
||||||
|
if (getter) {
|
||||||
|
return resolveEntities(getter, params[spec.id], (err, entities) => {
|
||||||
if (spec.minOccurences == 1 && spec.maxOccurences == 1) {
|
if (spec.minOccurences == 1 && spec.maxOccurences == 1) {
|
||||||
resolved[spec.id] = campaigns[0];
|
resolved[spec.id] = entities[0];
|
||||||
} else {
|
} else {
|
||||||
resolved[spec.id] = campaigns;
|
resolved[spec.id] = entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
doWork();
|
doWork();
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
return callback(new Error(_('Unknown user field type "' + spec.type + '".')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return callback(new Error(_('Unknown user field type "' + spec.type + '".')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setImmediate(doWork);
|
setImmediate(doWork);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addUserFields(reportTemplateId, reqData, template, callback) {
|
function addUserFields(reportTemplateId, reqData, report, callback) {
|
||||||
reportTemplates.get(reportTemplateId, (err, reportTemplate) => {
|
reportTemplates.get(reportTemplateId, (err, reportTemplate) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
@ -314,8 +342,8 @@ function addUserFields(reportTemplateId, reqData, template, callback) {
|
||||||
let value = '';
|
let value = '';
|
||||||
if ((spec.id + 'Selection') in reqData) {
|
if ((spec.id + 'Selection') in reqData) {
|
||||||
value = reqData[spec.id + 'Selection'];
|
value = reqData[spec.id + 'Selection'];
|
||||||
} else if (template && template.paramsObject && spec.id in template.paramsObject) {
|
} else if (report && report.paramsObject && spec.id in report.paramsObject) {
|
||||||
value = template.paramsObject[spec.id].join(',');
|
value = report.paramsObject[spec.id].join(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
userFields.push({
|
userFields.push({
|
||||||
|
@ -327,7 +355,7 @@ function addUserFields(reportTemplateId, reqData, template, callback) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = template ? template : reqData;
|
const data = report ? report : reqData;
|
||||||
data.userFields = userFields;
|
data.userFields = userFields;
|
||||||
|
|
||||||
callback(null, data);
|
callback(null, data);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<li><a href="/report-templates/create">{{#translate}}Blank{{/translate}}</a></li>
|
<li><a href="/report-templates/create">{{#translate}}Blank{{/translate}}</a></li>
|
||||||
<li><a href="/report-templates/create?type=subscribers-all">{{#translate}}All Subscribers{{/translate}}</a></li>
|
<li><a href="/report-templates/create?type=subscribers-all">{{#translate}}All Subscribers{{/translate}}</a></li>
|
||||||
<li><a href="/report-templates/create?type=subscribers-grouped">{{#translate}}Grouped Subscribers{{/translate}}</a></li>
|
<li><a href="/report-templates/create?type=subscribers-grouped">{{#translate}}Grouped Subscribers{{/translate}}</a></li>
|
||||||
|
<li><a href="/report-templates/create?type=export-list-csv">{{#translate}}Export List as CSV{{/translate}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -44,6 +44,30 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/case}}
|
{{/case}}
|
||||||
|
{{#case "list"}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="description" class="col-sm-2 control-label">{{name}}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table data-topic-url="/lists/quicklist" data-sort-column="2" data-sort-order="asc" class="table table-bordered table-hover data-table-ajax data-table-{{#if isMulti}}multi{{/if}}selectable display nowrap" width="100%" data-row-sort="0,1,1">
|
||||||
|
<thead>
|
||||||
|
<th class="col-md-1">
|
||||||
|
#
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{{#translate}}Name{{/translate}}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{{#translate}}Subscribers{{/translate}}
|
||||||
|
</th>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
<input type="hidden" name="{{id}}Selection" value="{{value}}" />
|
||||||
|
</div>
|
||||||
|
<span class="help-block">{{#translate}}Select a campaign in the table above by clicking on the respective row number.{{/translate}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/case}}
|
||||||
{{/switch}}
|
{{/switch}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue