Separate disable opened/clicked tracker to 2 options
This commit is contained in:
parent
5c0aab1c3e
commit
59912e3c29
13 changed files with 134 additions and 60 deletions
|
@ -16,7 +16,7 @@ let _ = require('../translate')._;
|
||||||
let util = require('util');
|
let util = require('util');
|
||||||
let tableHelpers = require('../table-helpers');
|
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'];
|
let allowedKeys = ['description', 'from', 'address', 'reply_to', 'subject', 'editor_name', 'editor_data', 'template', 'source_url', 'list', 'segment', 'html', 'text', 'click_tracking_disabled', 'open_tracking_disabled'];
|
||||||
|
|
||||||
module.exports.list = (start, limit, callback) => {
|
module.exports.list = (start, limit, callback) => {
|
||||||
tableHelpers.list('campaigns', ['*'], 'scheduled', null, start, limit, callback);
|
tableHelpers.list('campaigns', ['*'], 'scheduled', null, start, limit, callback);
|
||||||
|
@ -370,7 +370,8 @@ module.exports.create = (campaign, opts, callback) => {
|
||||||
campaign = tools.convertKeys(campaign);
|
campaign = tools.convertKeys(campaign);
|
||||||
let name = (campaign.name || '').toString().trim();
|
let name = (campaign.name || '').toString().trim();
|
||||||
|
|
||||||
campaign.trackingDisabled = campaign.trackingDisabled ? 1 : 0;
|
campaign.openTrackingDisabled = campaign.openTrackingDisabled ? 1 : 0;
|
||||||
|
campaign.clickTrackingDisabled = campaign.clickTrackingDisabled ? 1 : 0;
|
||||||
|
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
|
@ -592,7 +593,8 @@ module.exports.update = (id, updates, callback) => {
|
||||||
let campaign = tools.convertKeys(updates);
|
let campaign = tools.convertKeys(updates);
|
||||||
let name = (campaign.name || '').toString().trim();
|
let name = (campaign.name || '').toString().trim();
|
||||||
|
|
||||||
campaign.trackingDisabled = campaign.trackingDisabled ? 1 : 0;
|
campaign.openTrackingDisabled = campaign.openTrackingDisabled ? 1 : 0;
|
||||||
|
campaign.clickTrackingDisabled = campaign.clickTrackingDisabled ? 1 : 0;
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return callback(new Error(_('Campaign Name must be set')));
|
return callback(new Error(_('Campaign Name must be set')));
|
||||||
|
|
|
@ -42,7 +42,7 @@ module.exports.countClick = (remoteIp, useragent, campaignCid, listCid, subscrip
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data || data.campaign.trackingDisabled) {
|
if (!data || data.campaign.clickTrackingDisabled) {
|
||||||
return callback(null, false);
|
return callback(null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ module.exports.countOpen = (remoteIp, useragent, campaignCid, listCid, subscript
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data || data.campaign.trackingDisabled) {
|
if (!data || data.campaign.openTrackingDisabled) {
|
||||||
return callback(null, false);
|
return callback(null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,56 +268,64 @@ module.exports.add = (url, campaignId, callback) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.updateLinks = (campaign, list, subscription, serviceUrl, message, callback) => {
|
module.exports.updateLinks = (campaign, list, subscription, serviceUrl, message, callback) => {
|
||||||
if (campaign.trackingDisabled || !message || !message.trim()) {
|
if ((campaign.openTrackingDisabled && campaign.clickTrackingDisabled) || !message || !message.trim()) {
|
||||||
// tracking is disabled, do not modify the message
|
// tracking is disabled, do not modify the message
|
||||||
return setImmediate(() => callback(null, message));
|
return setImmediate(() => callback(null, message));
|
||||||
}
|
}
|
||||||
let re = /(<a[^>]* href\s*=[\s"']*)(http[^"'>\s]+)/gi;
|
|
||||||
let urls = new Set();
|
|
||||||
(message || '').replace(re, (match, prefix, url) => {
|
|
||||||
urls.add(url);
|
|
||||||
});
|
|
||||||
|
|
||||||
let map = new Map();
|
|
||||||
let vals = urls.values();
|
|
||||||
|
|
||||||
// insert tracking image
|
// insert tracking image
|
||||||
let inserted = false;
|
if (!campaign.openTrackingDisabled) {
|
||||||
let imgUrl = urllib.resolve(serviceUrl, util.format('/links/%s/%s/%s', campaign.cid, list.cid, encodeURIComponent(subscription.cid)));
|
let inserted = false;
|
||||||
let img = '<img src="' + imgUrl + '" width="1" height="1" alt="mt">';
|
let imgUrl = urllib.resolve(serviceUrl, util.format('/links/%s/%s/%s', campaign.cid, list.cid, encodeURIComponent(subscription.cid)));
|
||||||
message = message.replace(/<\/body\b/i, match => {
|
let img = '<img src="' + imgUrl + '" width="1" height="1" alt="mt">';
|
||||||
inserted = true;
|
message = message.replace(/<\/body\b/i, match => {
|
||||||
return img + match;
|
inserted = true;
|
||||||
});
|
return img + match;
|
||||||
if (!inserted) {
|
});
|
||||||
message = message + img;
|
if (!inserted) {
|
||||||
}
|
message = message + img;
|
||||||
|
}
|
||||||
let replaceUrls = () => {
|
if (campaign.clickTrackingDisabled) {
|
||||||
callback(null,
|
return callback(null, message);
|
||||||
message.replace(re, (match, prefix, url) =>
|
}
|
||||||
prefix + (map.has(url) ? urllib.resolve(serviceUrl, util.format('/links/%s/%s/%s/%s', campaign.cid, list.cid, encodeURIComponent(subscription.cid), encodeURIComponent(map.get(url)))) : url)));
|
}
|
||||||
};
|
|
||||||
|
if (!campaign.clickTrackingDisabled) {
|
||||||
let storeNext = () => {
|
let re = /(<a[^>]* href\s*=[\s"']*)(http[^"'>\s]+)/gi;
|
||||||
let urlItem = vals.next();
|
let urls = new Set();
|
||||||
if (urlItem.done) {
|
(message || '').replace(re, (match, prefix, url) => {
|
||||||
return replaceUrls();
|
urls.add(url);
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.add(he.decode(urlItem.value, {
|
|
||||||
isAttributeValue: true
|
|
||||||
}), campaign.id, (err, linkId, cid) => {
|
|
||||||
if (err) {
|
|
||||||
log.error('Link', err);
|
|
||||||
return storeNext();
|
|
||||||
}
|
|
||||||
map.set(urlItem.value, cid);
|
|
||||||
return storeNext();
|
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
storeNext();
|
let map = new Map();
|
||||||
|
let vals = urls.values();
|
||||||
|
|
||||||
|
let replaceUrls = () => {
|
||||||
|
callback(null,
|
||||||
|
message.replace(re, (match, prefix, url) =>
|
||||||
|
prefix + (map.has(url) ? urllib.resolve(serviceUrl, util.format('/links/%s/%s/%s/%s', campaign.cid, list.cid, encodeURIComponent(subscription.cid), encodeURIComponent(map.get(url)))) : url)));
|
||||||
|
};
|
||||||
|
|
||||||
|
let storeNext = () => {
|
||||||
|
let urlItem = vals.next();
|
||||||
|
if (urlItem.done) {
|
||||||
|
return replaceUrls();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.add(he.decode(urlItem.value, {
|
||||||
|
isAttributeValue: true
|
||||||
|
}), campaign.id, (err, linkId, cid) => {
|
||||||
|
if (err) {
|
||||||
|
log.error('Link', err);
|
||||||
|
return storeNext();
|
||||||
|
}
|
||||||
|
map.set(urlItem.value, cid);
|
||||||
|
return storeNext();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
storeNext();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function getSubscriptionData(campaignCid, listCid, subscriptionCid, callback) {
|
function getSubscriptionData(campaignCid, listCid, subscriptionCid, callback) {
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"schemaVersion": 27
|
"schemaVersion": 28
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,8 @@ CREATE TABLE `campaigns` (
|
||||||
`html_prepared` longtext,
|
`html_prepared` longtext,
|
||||||
`text` longtext,
|
`text` longtext,
|
||||||
`status` tinyint(4) unsigned NOT NULL DEFAULT '1',
|
`status` tinyint(4) unsigned NOT NULL DEFAULT '1',
|
||||||
`tracking_disabled` tinyint(4) unsigned NOT NULL DEFAULT '0',
|
`open_tracking_disabled` tinyint(4) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`click_tracking_disabled` tinyint(4) unsigned NOT NULL DEFAULT '0',
|
||||||
`scheduled` timestamp NULL DEFAULT NULL,
|
`scheduled` timestamp NULL DEFAULT NULL,
|
||||||
`status_change` timestamp NULL DEFAULT NULL,
|
`status_change` timestamp NULL DEFAULT NULL,
|
||||||
`delivered` int(11) unsigned NOT NULL DEFAULT '0',
|
`delivered` int(11) unsigned NOT NULL DEFAULT '0',
|
||||||
|
|
|
@ -65,7 +65,8 @@ CREATE TABLE `campaigns` (
|
||||||
`html_prepared` longtext,
|
`html_prepared` longtext,
|
||||||
`text` longtext,
|
`text` longtext,
|
||||||
`status` tinyint(4) unsigned NOT NULL DEFAULT '1',
|
`status` tinyint(4) unsigned NOT NULL DEFAULT '1',
|
||||||
`tracking_disabled` tinyint(4) unsigned NOT NULL DEFAULT '0',
|
`click_tracking_disabled` tinyint(4) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`open_tracking_disabled` tinyint(4) unsigned NOT NULL DEFAULT '0',
|
||||||
`scheduled` timestamp NULL DEFAULT NULL,
|
`scheduled` timestamp NULL DEFAULT NULL,
|
||||||
`status_change` timestamp NULL DEFAULT NULL,
|
`status_change` timestamp NULL DEFAULT NULL,
|
||||||
`delivered` int(11) unsigned NOT NULL DEFAULT '0',
|
`delivered` int(11) unsigned NOT NULL DEFAULT '0',
|
||||||
|
|
13
setup/sql/upgrade-00028.sql
Normal file
13
setup/sql/upgrade-00028.sql
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Header section
|
||||||
|
# Define incrementing schema version number
|
||||||
|
SET @schema_version = '28';
|
||||||
|
|
||||||
|
# Rename column tracking_disabled
|
||||||
|
ALTER TABLE `campaigns` ADD COLUMN `open_tracking_disabled` tinyint(4) unsigned DEFAULT 0 NOT NULL, ADD COLUMN `click_tracking_disabled` tinyint(4) unsigned DEFAULT 0 NOT NULL;
|
||||||
|
UPDATE `campaigns` SET `open_tracking_disabled` = `tracking_disabled`, `click_tracking_disabled` = `tracking_disabled`;
|
||||||
|
ALTER TABLE `campaigns` DROP COLUMN `tracking_disabled`;
|
||||||
|
|
||||||
|
# Footer section
|
||||||
|
LOCK TABLES `settings` WRITE;
|
||||||
|
INSERT INTO `settings` (`key`, `value`) VALUES('db_schema_version', @schema_version) ON DUPLICATE KEY UPDATE `value`=@schema_version;
|
||||||
|
UNLOCK TABLES;
|
|
@ -84,7 +84,15 @@
|
||||||
<div class="col-sm-offset-2">
|
<div class="col-sm-offset-2">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="tracking-disabled" value="1" {{#if trackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked/opened tracking{{/translate}}
|
<input type="checkbox" name="open-tracking-disabled" value="1" {{#if openTrackingDisabled}} checked {{/if}}> {{#translate}}Disable opened tracking{{/translate}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-offset-2">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="click-tracking-disabled" value="1" {{#if clickTrackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked tracking{{/translate}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -104,7 +104,15 @@
|
||||||
<div class="col-sm-offset-2">
|
<div class="col-sm-offset-2">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="tracking-disabled" value="1" {{#if trackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked/opened tracking{{/translate}}
|
<input type="checkbox" name="open-tracking-disabled" value="1" {{#if openTrackingDisabled}} checked {{/if}}> {{#translate}}Disable opened tracking{{/translate}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-offset-2">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="click-tracking-disabled" value="1" {{#if clickTrackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked tracking{{/translate}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -110,7 +110,15 @@
|
||||||
<div class="col-sm-offset-2">
|
<div class="col-sm-offset-2">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="tracking-disabled" value="1" {{#if trackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked/opened tracking{{/translate}}
|
<input type="checkbox" name="open-tracking-disabled" value="1" {{#if openTrackingDisabled}} checked {{/if}}> {{#translate}}Disable opened tracking{{/translate}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-offset-2">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="click-tracking-disabled" value="1" {{#if clickTrackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked tracking{{/translate}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -111,7 +111,15 @@
|
||||||
<div class="col-sm-offset-2">
|
<div class="col-sm-offset-2">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="tracking-disabled" value="1" {{#if trackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked/opened tracking{{/translate}}
|
<input type="checkbox" name="open-tracking-disabled" value="1" {{#if openTrackingDisabled}} checked {{/if}}> {{#translate}}Disable opened tracking{{/translate}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-offset-2">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="click-tracking-disabled" value="1" {{#if clickTrackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked tracking{{/translate}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -103,7 +103,15 @@
|
||||||
<div class="col-sm-offset-2">
|
<div class="col-sm-offset-2">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="tracking-disabled" value="1" {{#if trackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked/opened tracking{{/translate}}
|
<input type="checkbox" name="open-tracking-disabled" value="1" {{#if openTrackingDisabled}} checked {{/if}}> {{#translate}}Disable opened tracking{{/translate}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-offset-2">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="click-tracking-disabled" value="1" {{#if clickTrackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked tracking{{/translate}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -121,7 +121,15 @@
|
||||||
<div class="col-sm-offset-2">
|
<div class="col-sm-offset-2">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="tracking-disabled" value="1" {{#if trackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked/opened tracking{{/translate}}
|
<input type="checkbox" name="open-tracking-disabled" value="1" {{#if openTrackingDisabled}} checked {{/if}}> {{#translate}}Disable opened tracking{{/translate}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-offset-2">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="click-tracking-disabled" value="1" {{#if clickTrackingDisabled}} checked {{/if}}> {{#translate}}Disable clicked tracking{{/translate}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -164,7 +164,7 @@
|
||||||
</div>
|
</div>
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
{{#unless trackingDisabled}}
|
{{#unless openTrackingDisabled}}
|
||||||
|
|
||||||
<dt>{{#translate}}Opened{{/translate}} <a href="/campaigns/opened/{{id}}" title="{{#translate}}List subscribers who opened this message{{/translate}}"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
<dt>{{#translate}}Opened{{/translate}} <a href="/campaigns/opened/{{id}}" title="{{#translate}}List subscribers who opened this message{{/translate}}"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
@ -174,7 +174,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</dd>
|
</dd>
|
||||||
|
{{/unless}}
|
||||||
|
{{#unless clickTrackingDisabled}}
|
||||||
<dt>{{#translate}}Clicked{{/translate}} <a href="/campaigns/clicked/{{id}}/all" title="{{#translate}}List subscribers who clicked on a link{{/translate}}"> <span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
<dt>{{#translate}}Clicked{{/translate}} <a href="/campaigns/clicked/{{id}}/all" title="{{#translate}}List subscribers who clicked on a link{{/translate}}"> <span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue