diff --git a/lib/models/triggers.js b/lib/models/triggers.js index 6d2e49c6..b87125c4 100644 --- a/lib/models/triggers.js +++ b/lib/models/triggers.js @@ -1,8 +1,10 @@ 'use strict'; +let log = require('npmlog'); let tools = require('../tools'); let db = require('../db'); let lists = require('./lists'); +let segments = require('./segments'); let util = require('util'); let _ = require('../translate')._; let tableHelpers = require('../table-helpers'); @@ -55,7 +57,9 @@ module.exports.list = callback => { '`triggers`.`description` AS `description`', '`triggers`.`enabled` AS `enabled`', '`triggers`.`list` AS `list`', + '`triggers`.`segment` AS `segment`', '`lists`.`name` AS `list_name`', + '`segments`.`name` AS `segment_name`', '`source`.`id` AS `source_campaign`', '`source`.`name` AS `source_campaign_name`', '`dest`.`id` AS `dest_campaign`', @@ -69,7 +73,7 @@ module.exports.list = callback => { '`triggers`.`created` AS `created`' ]; - let query = 'SELECT ' + tableFields.join(', ') + ' FROM `triggers` LEFT JOIN `campaigns` `source` ON `source`.`id`=`triggers`.`source_campaign` LEFT JOIN `campaigns` `dest` ON `dest`.`id`=`triggers`.`dest_campaign` LEFT JOIN `lists` ON `lists`.`id`=`triggers`.`list` LEFT JOIN `custom_fields` ON `custom_fields`.`list` = `triggers`.`list` AND `custom_fields`.`column`=`triggers`.`column` ORDER BY `triggers`.`name`'; + let query = 'SELECT ' + tableFields.join(', ') + ' FROM `triggers` LEFT JOIN `campaigns` `source` ON `source`.`id`=`triggers`.`source_campaign` LEFT JOIN `campaigns` `dest` ON `dest`.`id`=`triggers`.`dest_campaign` LEFT JOIN `lists` ON `lists`.`id`=`triggers`.`list` LEFT JOIN `segments` ON `segments`.`id`=`triggers`.`segment` LEFT JOIN `custom_fields` ON `custom_fields`.`list` = `triggers`.`list` AND `custom_fields`.`column`=`triggers`.`column` ORDER BY `triggers`.`name`'; connection.query(query, (err, rows) => { connection.release(); if (err) { @@ -105,32 +109,70 @@ module.exports.getQuery = (id, callback) => { let intervalQuery = (column, seconds, treshold) => column + ' <= NOW() - INTERVAL ' + seconds + ' SECOND AND ' + column + ' >= NOW() - INTERVAL ' + (treshold + seconds) + ' SECOND'; - let query = false; - switch (trigger.rule) { - case 'subscription': - query = 'SELECT id FROM `subscription__' + trigger.list + '` subscription WHERE ' + intervalQuery('`' + trigger.column + '`', trigger.seconds, treshold) + ' AND id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; - break; - case 'campaign': - switch (trigger.column) { - case 'delivered': - query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription WHERE campaign.status=1 AND ' + intervalQuery('`campaign`.`created`', trigger.seconds, treshold) + ' AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; - break; - case 'not_clicked': - query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription LEFT JOIN `campaign_tracker__' + trigger.sourceCampaign + '` tracker ON tracker.list=campaign.list AND tracker.subscriber=subscription.id AND tracker.link=0 WHERE campaign.status=1 AND ' + intervalQuery('`campaign`.`created`', trigger.seconds, treshold) + ' AND tracker.created IS NULL AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; - break; - case 'not_opened': - query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription LEFT JOIN `campaign_tracker__' + trigger.sourceCampaign + '` tracker ON tracker.list=campaign.list AND tracker.subscriber=subscription.id AND tracker.link=-1 WHERE campaign.status=1 AND ' + intervalQuery('`campaign`.`created`', trigger.seconds, treshold) + ' AND tracker.created IS NULL AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; - break; - case 'clicked': - query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription LEFT JOIN `campaign_tracker__' + trigger.sourceCampaign + '` tracker ON tracker.list=campaign.list AND tracker.subscriber=subscription.id AND tracker.link=0 WHERE campaign.status=1 AND ' + intervalQuery('`tracker`.`created`', trigger.seconds, treshold) + ' AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; - break; - case 'opened': - query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription LEFT JOIN `campaign_tracker__' + trigger.sourceCampaign + '` tracker ON tracker.list=campaign.list AND tracker.subscriber=subscription.id AND tracker.link=-1 WHERE campaign.status=1 AND ' + intervalQuery('`tracker`.`created`', trigger.seconds, treshold) + ' AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; - break; + + let getSegmentQuery = (segmentId, next) => { + segmentId = Number(segmentId); + if (!segmentId) { + return next(null, { + where: '', + values: [] + }); + } + + segments.getQuery(segmentId, 'subscription', next); + }; + + getSegmentQuery(trigger.segment, (err, queryData) => { + if (err) { + log.err('Triggers', err); + return null; + } + + let query = false; + let querySegmentSubscription = ''; + let querySegmentTriggertable = ''; + if (trigger.segment > 0) + { + querySegmentSubscription = (queryData.where ? ' AND (' + queryData.where + ')' : ''); + querySegmentTriggertable = ' AND triggertable.`segment` = ' + trigger.segment; + } + + switch (trigger.rule) { + case 'subscription': + query = 'SELECT id FROM `subscription__' + trigger.list + '` subscription WHERE status=1 AND ' + intervalQuery('`' + trigger.column + '`', trigger.seconds, treshold) + ' ' + querySegmentSubscription + ' AND id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' ' + querySegmentTriggertable + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; + break; + case 'campaign': + switch (trigger.column) { + case 'delivered': + query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription WHERE campaign.status=1 AND ' + intervalQuery('`campaign`.`created`', trigger.seconds, treshold) + ' ' + querySegmentSubscription + ' AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' ' + querySegmentTriggertable + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; + break; + case 'not_clicked': + query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription LEFT JOIN `campaign_tracker__' + trigger.sourceCampaign + '` tracker ON tracker.list=campaign.list AND tracker.subscriber=subscription.id AND tracker.link=0 WHERE campaign.status=1 AND ' + intervalQuery('`campaign`.`created`', trigger.seconds, treshold) + ' AND tracker.created IS NULL ' + querySegmentSubscription + ' AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' ' + querySegmentTriggertable + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; + break; + case 'not_opened': + query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription LEFT JOIN `campaign_tracker__' + trigger.sourceCampaign + '` tracker ON tracker.list=campaign.list AND tracker.subscriber=subscription.id AND tracker.link=-1 WHERE campaign.status=1 AND ' + intervalQuery('`campaign`.`created`', trigger.seconds, treshold) + ' AND tracker.created IS NULL ' + querySegmentSubscription + ' AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' ' + querySegmentTriggertable + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; + break; + case 'clicked': + query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription LEFT JOIN `campaign_tracker__' + trigger.sourceCampaign + '` tracker ON tracker.list=campaign.list AND tracker.subscriber=subscription.id AND tracker.link=0 WHERE campaign.status=1 AND ' + intervalQuery('`tracker`.`created`', trigger.seconds, treshold) + ' ' + querySegmentSubscription + ' AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' ' + querySegmentTriggertable + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; + break; + case 'opened': + query = 'SELECT subscription.id AS id FROM `subscription__' + trigger.list + '` subscription LEFT JOIN `campaign__' + trigger.sourceCampaign + '` campaign ON campaign.list=' + trigger.list + ' AND subscription.id=campaign.subscription LEFT JOIN `campaign_tracker__' + trigger.sourceCampaign + '` tracker ON tracker.list=campaign.list AND tracker.subscriber=subscription.id AND tracker.link=-1 WHERE campaign.status=1 AND ' + intervalQuery('`tracker`.`created`', trigger.seconds, treshold) + ' ' + querySegmentSubscription + ' AND subscription.id NOT IN (SELECT subscription FROM `trigger__' + id + '` triggertable WHERE triggertable.`list` = ' + trigger.list + ' ' + querySegmentTriggertable + ' AND triggertable.`subscription` = subscription.`id`) LIMIT ' + limit; + break; + } + break; + } + + if (trigger.segment > 0) { + let values = queryData.values.concat([trigger.list, trigger.segment]); + for (let i = 0; i < values.length; i++) { + query = query.replace('?', db.escape(values[i])); } - break; - } - callback(null, query); + } + + callback(null, query); + + }); + }); }; @@ -168,6 +210,7 @@ module.exports.create = (trigger, callback) => { let name = (trigger.name || '').toString().trim(); let description = (trigger.description || '').toString().trim(); let listId = Number(trigger.list) || 0; + let segmentId = Number(trigger.segmentId) || 0; let seconds = (Number(trigger.days) || 0) * 24 * 3600; let rule = (trigger.rule || '').toString().toLowerCase().trim(); let destCampaign = Number(trigger.destCampaign) || 0; @@ -220,8 +263,8 @@ module.exports.create = (trigger, callback) => { return callback(err); } - let keys = ['name', 'description', 'list', 'source_campaign', 'rule', 'column', 'seconds', 'dest_campaign', 'last_check']; - let values = [name, description, list.id, sourceCampaign, rule, column, seconds, destCampaign]; + let keys = ['name', 'description', 'list', 'segment', 'source_campaign', 'rule', 'column', 'seconds', 'dest_campaign', 'last_check']; + let values = [name, description, list.id, segmentId, sourceCampaign, rule, column, seconds, destCampaign]; let query = 'INSERT INTO `triggers` (`' + keys.join('`, `') + '`) VALUES (' + values.map(() => '?').join(', ') + ', NOW())'; diff --git a/services/triggers.js b/services/triggers.js index d223c573..c08013c7 100644 --- a/services/triggers.js +++ b/services/triggers.js @@ -82,8 +82,8 @@ function fireTrigger(trigger, callback) { } let subscriber = rows[pos++].id; - let query = 'INSERT INTO `trigger__' + trigger.id + '` (`list`, `subscription`) VALUES (?,?)'; - let values = [trigger.list, subscriber]; + let query = 'INSERT INTO `trigger__' + trigger.id + '` (`list`, `segment`, `subscription`) VALUES (?,?,?)'; + let values = [trigger.list, trigger.segment, subscriber]; connection.query(query, values, (err, result) => { if (err && err.code !== 'ER_DUP_ENTRY') { diff --git a/setup/sql/upgrade-00030.sql b/setup/sql/upgrade-00030.sql new file mode 100644 index 00000000..66560e04 --- /dev/null +++ b/setup/sql/upgrade-00030.sql @@ -0,0 +1,12 @@ +# Header section +# Define incrementing schema version number +SET @schema_version = '30'; + +# Add segment support for triggers +ALTER TABLE `triggers` ADD `segment` INT(11) UNSIGNED NOT NULL AFTER `list`; +ALTER TABLE `trigger` ADD `segment` INT(11) UNSIGNED NOT NULL AFTER `list`; + +# 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;