2016-04-04 12:36:30 +00:00
'use strict' ;
let db = require ( '../db' ) ;
let shortid = require ( 'shortid' ) ;
2017-06-02 22:13:03 +00:00
let striptags = require ( 'striptags' ) ;
2016-04-04 12:36:30 +00:00
let tools = require ( '../tools' ) ;
2017-03-19 12:36:57 +00:00
let helpers = require ( '../helpers' ) ;
2016-04-04 12:36:30 +00:00
let fields = require ( './fields' ) ;
let segments = require ( './segments' ) ;
2017-03-07 14:30:56 +00:00
let _ = require ( '../translate' ) . _ ;
2017-04-15 12:24:58 +00:00
let tableHelpers = require ( '../table-helpers' ) ;
2016-04-04 12:36:30 +00:00
2017-05-04 21:42:46 +00:00
const Status = {
SUBSCRIBED : 1 ,
UNSUBSCRIBED : 2 ,
BOUNCED : 3 ,
COMPLAINED : 4 ,
MAX : 5
} ;
module . exports . Status = Status ;
2016-04-04 12:36:30 +00:00
module . exports . list = ( listId , start , limit , callback ) => {
listId = Number ( listId ) || 0 ;
if ( ! listId ) {
return callback ( new Error ( 'Missing List ID' ) ) ;
}
2017-04-20 23:42:01 +00:00
tableHelpers . list ( 'subscription__' + listId , [ '*' ] , 'email' , null , start , limit , ( err , rows , total ) => {
2017-04-15 12:24:58 +00:00
if ( ! err ) {
rows = rows . map ( row => tools . convertKeys ( row ) ) ;
2016-04-04 12:36:30 +00:00
}
2017-04-15 12:24:58 +00:00
return callback ( err , rows , total ) ;
2016-04-04 12:36:30 +00:00
} ) ;
} ;
2016-05-31 14:32:36 +00:00
module . exports . listTestUsers = ( listId , callback ) => {
listId = Number ( listId ) || 0 ;
if ( listId < 1 ) {
return callback ( new Error ( 'Missing List ID' ) ) ;
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
connection . query ( 'SELECT id, cid, email, first_name, last_name FROM `subscription__' + listId + '` WHERE is_test=1 LIMIT 100' , ( err , rows ) => {
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
if ( ! rows || ! rows . length ) {
return callback ( null , [ ] ) ;
}
let subscribers = rows . map ( subscriber => {
subscriber = tools . convertKeys ( subscriber ) ;
let fullName = [ ] . concat ( subscriber . firstName || [ ] ) . concat ( subscriber . lastName || [ ] ) . join ( ' ' ) ;
if ( fullName ) {
subscriber . displayName = fullName + ' <' + subscriber . email + '>' ;
} else {
subscriber . displayName = subscriber . email ;
}
return subscriber ;
} ) ;
return callback ( null , subscribers ) ;
} ) ;
} ) ;
} ;
2016-04-04 12:36:30 +00:00
module . exports . filter = ( listId , request , columns , segmentId , callback ) => {
listId = Number ( listId ) || 0 ;
segmentId = Number ( segmentId ) || 0 ;
if ( ! listId ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing List ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
if ( segmentId ) {
2016-05-25 15:01:39 +00:00
segments . getQuery ( segmentId , false , ( err , queryData ) => {
2016-04-04 12:36:30 +00:00
if ( err ) {
return callback ( err ) ;
}
2017-04-15 12:24:58 +00:00
2017-04-16 07:22:32 +00:00
tableHelpers . filter ( 'subscription__' + listId , [ '*' ] , request , columns , [ 'email' , 'first_name' , 'last_name' ] , 'email ASC' , queryData , callback ) ;
2016-04-04 12:36:30 +00:00
} ) ;
} else {
2017-04-16 07:22:32 +00:00
tableHelpers . filter ( 'subscription__' + listId , [ '*' ] , request , columns , [ 'email' , 'first_name' , 'last_name' ] , 'email ASC' , null , callback ) ;
2016-04-04 12:36:30 +00:00
}
} ;
2017-05-03 19:46:49 +00:00
/ *
Adds a new subscription . Returns error if a subscription with the same email address is already present and is not unsubscribed .
If it is unsubscribed , the existing subscription is changed based on the provided data .
If meta . partial is true , it updates even an active subscription .
* /
module . exports . insert = ( listId , meta , subscriptionData , callback ) => {
2016-04-04 12:36:30 +00:00
meta = tools . convertKeys ( meta ) ;
2017-05-03 19:46:49 +00:00
subscriptionData = tools . convertKeys ( subscriptionData ) ;
2016-04-04 12:36:30 +00:00
2017-05-03 19:46:49 +00:00
meta . email = meta . email || subscriptionData . email ;
2016-04-04 12:36:30 +00:00
meta . cid = meta . cid || shortid . generate ( ) ;
fields . list ( listId , ( err , fieldList ) => {
if ( err ) {
return callback ( err ) ;
}
let insertKeys = [ 'email' , 'cid' , 'opt_in_ip' , 'opt_in_country' , 'imported' ] ;
let insertValues = [ meta . email , meta . cid , meta . optInIp || null , meta . optInCountry || null , meta . imported || null ] ;
let keys = [ ] ;
let values = [ ] ;
2016-05-31 14:32:36 +00:00
let allowedKeys = [ 'first_name' , 'last_name' , 'tz' , 'is_test' ] ;
2017-05-03 19:46:49 +00:00
Object . keys ( subscriptionData ) . forEach ( key => {
let value = subscriptionData [ key ] ;
2016-04-04 12:36:30 +00:00
key = tools . toDbKey ( key ) ;
2016-04-29 16:13:51 +00:00
if ( key === 'tz' ) {
value = ( value || '' ) . toString ( ) . toLowerCase ( ) . trim ( ) ;
}
2016-05-31 14:32:36 +00:00
if ( key === 'is_test' ) {
value = value ? '1' : '0' ;
}
2016-04-04 12:36:30 +00:00
if ( allowedKeys . indexOf ( key ) >= 0 ) {
keys . push ( key ) ;
values . push ( value ) ;
}
} ) ;
2017-05-03 19:46:49 +00:00
fields . getValues ( fields . getRow ( fieldList , subscriptionData , true , true , ! ! meta . partial ) , true ) . forEach ( field => {
2016-04-04 12:36:30 +00:00
keys . push ( field . key ) ;
values . push ( field . value ) ;
} ) ;
2017-06-02 22:13:03 +00:00
values = values . map ( v => typeof v === 'string' ? striptags ( v ) : v ) ;
2016-04-04 12:36:30 +00:00
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
connection . beginTransaction ( err => {
if ( err ) {
2016-06-22 12:25:36 +00:00
connection . release ( ) ;
2016-04-04 12:36:30 +00:00
return callback ( err ) ;
}
2016-05-12 16:21:56 +00:00
let query = 'SELECT `id`, `status`, `cid` FROM `subscription__' + listId + '` WHERE `email`=? OR `cid`=? LIMIT 1' ;
2016-04-04 12:36:30 +00:00
connection . query ( query , [ meta . email , meta . cid ] , ( err , rows ) => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
let query ;
let queryArgs ;
let existing = rows && rows [ 0 ] || false ;
let entryId = existing ? existing . id : false ;
2016-05-12 16:21:56 +00:00
meta . cid = existing ? rows [ 0 ] . cid : meta . cid ;
2017-05-04 21:42:46 +00:00
meta . status = meta . status || ( existing ? existing . status : Status . SUBSCRIBED ) ;
2016-04-04 12:36:30 +00:00
let statusChange = ! existing || existing . status !== meta . status ;
let statusDirection ;
2017-05-04 21:42:46 +00:00
if ( existing && existing . status === Status . SUBSCRIBED && ! meta . partial ) {
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( new Error ( _ ( 'Email address already registered' ) ) ) ) ;
2017-05-03 19:46:49 +00:00
}
2016-04-04 12:36:30 +00:00
if ( statusChange ) {
keys . push ( 'status' , 'status_change' ) ;
values . push ( meta . status , new Date ( ) ) ;
2017-05-04 21:42:46 +00:00
statusDirection = ! existing ? ( meta . status === Status . SUBSCRIBED ? '+' : false ) : ( existing . status === Status . SUBSCRIBED ? '-' : '+' ) ;
2016-04-04 12:36:30 +00:00
}
2016-05-13 17:08:42 +00:00
if ( ! keys . length ) {
// nothing to update
return connection . commit ( err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-05-13 17:08:42 +00:00
}
connection . release ( ) ;
return callback ( null , {
entryId ,
cid : meta . cid ,
inserted : ! existing
} ) ;
} ) ;
}
2016-04-04 12:36:30 +00:00
if ( ! existing ) {
// insert as new
keys = insertKeys . concat ( keys ) ;
queryArgs = values = insertValues . concat ( values ) ;
query = 'INSERT INTO `subscription__' + listId + '` (`' + keys . join ( '`, `' ) + '`) VALUES (' + keys . map ( ( ) => '?' ) . join ( ',' ) + ')' ;
} else {
// update existing
queryArgs = values . concat ( existing . id ) ;
query = 'UPDATE `subscription__' + listId + '` SET ' + keys . map ( key => '`' + key + '`=?' ) + ' WHERE id=? LIMIT 1' ;
}
connection . query ( query , queryArgs , ( err , result ) => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
entryId = result . insertId || entryId ;
2016-08-11 07:56:16 +00:00
if ( statusChange && statusDirection ) {
2016-04-04 12:36:30 +00:00
connection . query ( 'UPDATE lists SET `subscribers`=`subscribers`' + statusDirection + '1 WHERE id=?' , [ listId ] , err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
connection . commit ( err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
connection . release ( ) ;
2016-04-25 12:39:17 +00:00
return callback ( null , {
entryId ,
2016-05-12 16:21:56 +00:00
cid : meta . cid ,
2016-04-25 12:39:17 +00:00
inserted : ! existing
} ) ;
2016-04-04 12:36:30 +00:00
} ) ;
} ) ;
} else {
connection . commit ( err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
connection . release ( ) ;
2016-04-25 12:39:17 +00:00
return callback ( null , {
entryId ,
2016-05-12 16:21:56 +00:00
cid : meta . cid ,
2016-04-25 12:39:17 +00:00
inserted : ! existing
} ) ;
2016-04-04 12:36:30 +00:00
} ) ;
}
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
module . exports . get = ( listId , cid , callback ) => {
cid = ( cid || '' ) . toString ( ) . trim ( ) ;
if ( ! cid ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing Subbscription ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
connection . query ( 'SELECT * FROM `subscription__' + listId + '` WHERE cid=?' , [ cid ] , ( err , rows ) => {
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
if ( ! rows || ! rows . length ) {
return callback ( null , false ) ;
}
2016-04-21 17:17:19 +00:00
let subscription = tools . convertKeys ( rows [ 0 ] ) ;
2016-05-04 13:54:09 +00:00
// ensure list id in response
subscription . list = subscription . list || listId ;
return callback ( null , subscription ) ;
} ) ;
} ) ;
} ;
module . exports . getById = ( listId , id , callback ) => {
id = Number ( id ) || 0 ;
if ( ! id ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing Subbscription ID' ) ) ) ;
2016-05-04 13:54:09 +00:00
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
connection . query ( 'SELECT * FROM `subscription__' + listId + '` WHERE id=?' , [ id ] , ( err , rows ) => {
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
if ( ! rows || ! rows . length ) {
return callback ( null , false ) ;
}
2016-06-24 11:29:07 +00:00
let subscription = tools . convertKeys ( rows [ 0 ] ) ;
// ensure list id in response
subscription . list = subscription . list || listId ;
return callback ( null , subscription ) ;
} ) ;
} ) ;
} ;
module . exports . getByEmail = ( listId , email , callback ) => {
if ( ! email ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing Subbscription email address' ) ) ) ;
2016-06-24 11:29:07 +00:00
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
connection . query ( 'SELECT * FROM `subscription__' + listId + '` WHERE email=?' , [ email ] , ( err , rows ) => {
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
if ( ! rows || ! rows . length ) {
return callback ( null , false ) ;
}
2016-05-04 13:54:09 +00:00
let subscription = tools . convertKeys ( rows [ 0 ] ) ;
// ensure list id in response
subscription . list = subscription . list || listId ;
2016-04-21 17:17:19 +00:00
return callback ( null , subscription ) ;
2016-04-04 12:36:30 +00:00
} ) ;
} ) ;
} ;
2016-04-25 13:19:55 +00:00
module . exports . getWithMergeTags = ( listId , cid , callback ) => {
module . exports . get ( listId , cid , ( err , subscription ) => {
if ( err ) {
return callback ( err ) ;
}
if ( ! subscription ) {
return callback ( null , false ) ;
}
fields . list ( listId , ( err , fieldList ) => {
if ( err || ! fieldList ) {
return fieldList = [ ] ;
}
subscription . mergeTags = {
EMAIL : subscription . email ,
FIRST _NAME : subscription . firstName ,
LAST _NAME : subscription . lastName ,
2016-04-29 11:57:13 +00:00
FULL _NAME : [ ] . concat ( subscription . firstName || [ ] ) . concat ( subscription . lastName || [ ] ) . join ( ' ' ) ,
TIMEZONE : subscription . tz || ''
2016-04-25 13:19:55 +00:00
} ;
2017-06-01 22:24:26 +00:00
fields . getRow ( fieldList , subscription , false , true ) . forEach ( field => {
2016-04-25 13:19:55 +00:00
if ( field . mergeTag ) {
subscription . mergeTags [ field . mergeTag ] = field . mergeValue || '' ;
}
if ( field . options ) {
field . options . forEach ( subField => {
if ( subField . mergeTag ) {
subscription . mergeTags [ subField . mergeTag ] = subField . mergeValue || '' ;
}
} ) ;
}
} ) ;
return callback ( null , subscription ) ;
} ) ;
} ) ;
} ;
2016-04-04 12:36:30 +00:00
module . exports . update = ( listId , cid , updates , allowEmail , callback ) => {
updates = tools . convertKeys ( updates ) ;
listId = Number ( listId ) || 0 ;
cid = ( cid || '' ) . toString ( ) . trim ( ) ;
let keys = [ ] ;
let values = [ ] ;
if ( listId < 1 ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing List ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
if ( ! cid ) {
2017-05-03 19:46:49 +00:00
return callback ( new Error ( _ ( 'Missing Subscription ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
fields . list ( listId , ( err , fieldList ) => {
if ( err ) {
return callback ( err ) ;
}
2016-05-31 14:32:36 +00:00
let allowedKeys = [ 'first_name' , 'last_name' , 'tz' , 'is_test' ] ;
2016-04-04 12:36:30 +00:00
if ( allowEmail ) {
allowedKeys . unshift ( 'email' ) ;
}
Object . keys ( updates ) . forEach ( key => {
let value = updates [ key ] ;
key = tools . toDbKey ( key ) ;
2016-04-29 16:13:51 +00:00
if ( key === 'tz' ) {
value = ( value || '' ) . toString ( ) . toLowerCase ( ) . trim ( ) ;
}
2016-04-04 12:36:30 +00:00
if ( allowedKeys . indexOf ( key ) >= 0 ) {
keys . push ( key ) ;
values . push ( value ) ;
}
} ) ;
fields . getValues ( fields . getRow ( fieldList , updates , true , true ) , true ) . forEach ( field => {
keys . push ( field . key ) ;
values . push ( field . value ) ;
} ) ;
if ( ! values . length ) {
return callback ( null , false ) ;
}
2017-06-02 22:13:03 +00:00
values = values . map ( v => typeof v === 'string' ? striptags ( v ) : v ) ;
2016-04-04 12:36:30 +00:00
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
values . push ( cid ) ;
connection . query ( 'UPDATE `subscription__' + listId + '` SET ' + keys . map ( key => '`' + key + '`=?' ) . join ( ', ' ) + ' WHERE `cid`=? LIMIT 1' , values , ( err , result ) => {
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
return callback ( null , result && result . affectedRows || false ) ;
} ) ;
} ) ;
} ) ;
} ;
2017-05-03 19:46:49 +00:00
module . exports . changeStatus = ( listId , id , campaignId , status , callback ) => {
2016-04-04 12:36:30 +00:00
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
connection . beginTransaction ( err => {
if ( err ) {
2016-06-22 12:25:36 +00:00
connection . release ( ) ;
2016-04-04 12:36:30 +00:00
return callback ( err ) ;
}
connection . query ( 'SELECT `status` FROM `subscription__' + listId + '` WHERE id=? LIMIT 1' , [ id ] , ( err , rows ) => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
if ( ! rows || ! rows . length ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( null , false ) ) ;
2016-04-04 12:36:30 +00:00
}
let oldStatus = rows [ 0 ] . status ;
let statusChange = oldStatus !== status ;
let statusDirection ;
if ( ! statusChange ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( null , true ) ) ;
2016-04-04 12:36:30 +00:00
}
2017-05-04 21:42:46 +00:00
if ( statusChange && oldStatus === Status . SUBSCRIBED || status === Status . SUBSCRIBED ) {
statusDirection = status === Status . SUBSCRIBED ? '+' : '-' ;
2016-04-04 12:36:30 +00:00
}
connection . query ( 'UPDATE `subscription__' + listId + '` SET `status`=?, `status_change`=NOW() WHERE id=? LIMIT 1' , [ status , id ] , err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
if ( ! statusDirection ) {
return connection . commit ( err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
connection . release ( ) ;
return callback ( null , true ) ;
} ) ;
}
connection . query ( 'UPDATE `lists` SET `subscribers`=`subscribers`' + statusDirection + '1 WHERE id=? LIMIT 1' , [ listId ] , err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
2016-05-25 10:47:14 +00:00
// status change is not related to a campaign or it marks message as bounced etc.
2017-06-08 12:22:34 +00:00
if ( ! campaignId || status !== Status . SUBSCRIBED && status !== Status . UNSUBSCRIBED ) {
2016-04-04 12:36:30 +00:00
return connection . commit ( err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
connection . release ( ) ;
return callback ( null , true ) ;
} ) ;
}
2016-05-25 10:47:14 +00:00
connection . query ( 'SELECT `id` FROM `campaigns` WHERE `cid`=? LIMIT 1' , [ campaignId ] , ( err , rows ) => {
2016-04-04 12:36:30 +00:00
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
2016-05-25 10:47:14 +00:00
let campaign = rows && rows [ 0 ] || false ;
if ( ! campaign ) {
// should not happend
return connection . commit ( err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-05-25 10:47:14 +00:00
}
connection . release ( ) ;
return callback ( null , true ) ;
} ) ;
}
// we should see only unsubscribe events here but you never know
2017-05-04 21:42:46 +00:00
connection . query ( 'UPDATE `campaigns` SET `unsubscribed`=`unsubscribed`' + ( status === Status . UNSUBSCRIBED ? '+' : '-' ) + '1 WHERE `cid`=? LIMIT 1' , [ campaignId ] , err => {
2016-04-04 12:36:30 +00:00
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
2016-05-25 10:47:14 +00:00
let query = 'UPDATE `campaign__' + campaign . id + '` SET `status`=? WHERE `list`=? AND `subscription`=? LIMIT 1' ;
let values = [ status , listId , id ] ;
// Updated tracker status
connection . query ( query , values , err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-05-25 10:47:14 +00:00
}
return connection . commit ( err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-05-25 10:47:14 +00:00
}
connection . release ( ) ;
return callback ( null , true ) ;
} ) ;
} ) ;
2016-04-04 12:36:30 +00:00
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
module . exports . delete = ( listId , cid , callback ) => {
listId = Number ( listId ) || 0 ;
cid = ( cid || '' ) . toString ( ) . trim ( ) ;
if ( listId < 1 ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing List ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
if ( ! cid ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing subscription ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
connection . query ( 'SELECT id, email, status FROM `subscription__' + listId + '` WHERE cid=? LIMIT 1' , [ cid ] , ( err , rows ) => {
if ( err ) {
connection . release ( ) ;
return callback ( err ) ;
}
let subscription = rows && rows [ 0 ] ;
if ( ! subscription ) {
connection . release ( ) ;
return callback ( null , false ) ;
}
connection . beginTransaction ( err => {
if ( err ) {
2016-06-22 12:25:36 +00:00
connection . release ( ) ;
2016-04-04 12:36:30 +00:00
return callback ( err ) ;
}
connection . query ( 'DELETE FROM `subscription__' + listId + '` WHERE cid=? LIMIT 1' , [ cid ] , err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
2017-05-04 21:42:46 +00:00
if ( subscription . status !== Status . SUBSCRIBED ) {
2016-04-04 12:36:30 +00:00
return connection . commit ( err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
connection . release ( ) ;
return callback ( null , subscription . email ) ;
} ) ;
}
connection . query ( 'UPDATE lists SET subscribers=subscribers-1 WHERE id=? LIMIT 1' , [ listId ] , err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
connection . commit ( err => {
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2016-04-04 12:36:30 +00:00
}
connection . release ( ) ;
return callback ( null , subscription . email ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
2017-03-31 09:20:43 +00:00
module . exports . createImport = ( listId , type , path , size , delimiter , emailcheck , mapping , callback ) => {
2016-04-04 12:36:30 +00:00
listId = Number ( listId ) || 0 ;
type = Number ( type ) || 1 ;
if ( listId < 1 ) {
return callback ( new Error ( 'Missing List ID' ) ) ;
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
2017-03-31 09:20:43 +00:00
let query = 'INSERT INTO importer (`list`, `type`, `path`, `size`, `delimiter`, `emailcheck`, `mapping`) VALUES(?,?,?,?,?,?,?)' ;
connection . query ( query , [ listId , type , path , size , delimiter , emailcheck , JSON . stringify ( mapping ) ] , ( err , result ) => {
2016-04-04 12:36:30 +00:00
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
return callback ( null , result && result . insertId || false ) ;
} ) ;
} ) ;
} ;
module . exports . updateImport = ( listId , importId , data , callback ) => {
listId = Number ( listId ) || 0 ;
importId = Number ( importId ) || 0 ;
if ( listId < 1 ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing List ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
if ( importId < 1 ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing Import ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
let keys = [ ] ;
let values = [ ] ;
2016-04-25 12:39:17 +00:00
let allowedKeys = [ 'type' , 'path' , 'size' , 'delimiter' , 'status' , 'error' , 'processed' , 'new' , 'failed' , 'mapping' , 'finished' ] ;
2016-04-04 12:36:30 +00:00
Object . keys ( data ) . forEach ( key => {
let value = data [ key ] ;
key = tools . toDbKey ( key ) ;
if ( allowedKeys . indexOf ( key ) >= 0 ) {
keys . push ( key ) ;
values . push ( value ) ;
}
} ) ;
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
let query = 'UPDATE importer SET ' + keys . map ( key => '`' + key + '`=?' ) + ' WHERE id=? AND list=? LIMIT 1' ;
connection . query ( query , values . concat ( [ importId , listId ] ) , ( err , result ) => {
if ( err ) {
2016-04-25 12:39:17 +00:00
connection . release ( ) ;
2016-04-04 12:36:30 +00:00
return callback ( err ) ;
}
2016-04-25 12:39:17 +00:00
let affected = result && result . affectedRows || false ;
if ( data . failed === 0 ) {
// remove entries from import_failed table
let query = 'DELETE FROM `import_failed` WHERE `import`=?' ;
connection . query ( query , [ importId ] , ( ) => {
connection . release ( ) ;
return callback ( null , affected ) ;
} ) ;
2017-05-04 21:42:46 +00:00
} else {
connection . release ( ) ;
return callback ( null , affected ) ;
2016-04-25 12:39:17 +00:00
}
2016-04-04 12:36:30 +00:00
} ) ;
} ) ;
} ;
module . exports . getImport = ( listId , importId , callback ) => {
listId = Number ( listId ) || 0 ;
importId = Number ( importId ) || 0 ;
if ( listId < 1 ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing List ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
if ( importId < 1 ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing Import ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
let query = 'SELECT * FROM importer WHERE id=? AND list=? LIMIT 1' ;
connection . query ( query , [ importId , listId ] , ( err , rows ) => {
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
if ( ! rows || ! rows . length ) {
return callback ( null , false ) ;
}
let importer = tools . convertKeys ( rows [ 0 ] ) ;
try {
importer . mapping = JSON . parse ( importer . mapping ) ;
} catch ( E ) {
importer . mapping = {
columns : [ ]
} ;
}
return callback ( null , importer ) ;
} ) ;
} ) ;
} ;
2016-04-25 12:39:17 +00:00
module . exports . getFailedImports = ( importId , callback ) => {
importId = Number ( importId ) || 0 ;
if ( importId < 1 ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing Import ID' ) ) ) ;
2016-04-25 12:39:17 +00:00
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
let query = 'SELECT * FROM import_failed WHERE import=? LIMIT 1000' ;
connection . query ( query , [ importId ] , ( err , rows ) => {
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
return callback ( null , ( rows || [ ] ) . map ( tools . convertKeys ) ) ;
} ) ;
} ) ;
} ;
2016-04-04 12:36:30 +00:00
module . exports . listImports = ( listId , callback ) => {
listId = Number ( listId ) || 0 ;
if ( listId < 1 ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing List ID' ) ) ) ;
2016-04-04 12:36:30 +00:00
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
let query = 'SELECT * FROM importer WHERE list=? AND status > 0 ORDER BY id DESC' ;
connection . query ( query , [ listId ] , ( err , rows ) => {
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
if ( ! rows || ! rows . length ) {
return callback ( null , [ ] ) ;
}
let imports = rows . map ( row => {
let importer = tools . convertKeys ( row ) ;
try {
importer . mapping = JSON . parse ( importer . mapping ) ;
} catch ( E ) {
importer . mapping = {
columns : [ ]
} ;
}
return importer ;
} ) ;
return callback ( null , imports ) ;
} ) ;
} ) ;
} ;
2016-12-07 14:12:26 +00:00
2017-05-03 19:46:49 +00:00
/ *
Performs checks before update of an address . This includes finding the existing subscriber , validating the new email
and checking whether the new email does not conflict with other subscribers .
* /
module . exports . updateAddressCheck = ( list , cid , emailNew , ip , callback ) => {
2016-12-07 14:12:26 +00:00
cid = ( cid || '' ) . toString ( ) . trim ( ) ;
if ( ! list || ! list . id ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing List ID' ) ) ) ;
2016-12-07 14:12:26 +00:00
}
if ( ! cid ) {
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Missing subscription ID' ) ) ) ;
2016-12-07 14:12:26 +00:00
}
tools . validateEmail ( emailNew , false , err => {
if ( err ) {
return callback ( err ) ;
}
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
2017-05-04 21:42:46 +00:00
let query = 'SELECT * FROM `subscription__' + list . id + '` WHERE `cid`=? AND `status`=' + Status . SUBSCRIBED + ' LIMIT 1' ;
2016-12-07 14:12:26 +00:00
let args = [ cid ] ;
connection . query ( query , args , ( err , rows ) => {
if ( err ) {
2016-12-07 14:21:22 +00:00
connection . release ( ) ;
2016-12-07 14:12:26 +00:00
return callback ( err ) ;
}
if ( ! rows || ! rows . length ) {
2016-12-07 14:21:22 +00:00
connection . release ( ) ;
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Unknown subscription ID' ) ) ) ;
2016-12-07 14:12:26 +00:00
}
if ( rows [ 0 ] . email === emailNew ) {
2016-12-07 14:21:22 +00:00
connection . release ( ) ;
2017-03-07 14:30:56 +00:00
return callback ( new Error ( _ ( 'Nothing seems to be changed' ) ) ) ;
2016-12-07 14:12:26 +00:00
}
2016-12-07 14:21:22 +00:00
let old = rows [ 0 ] ;
2017-05-04 21:42:46 +00:00
let query = 'SELECT `id` FROM `subscription__' + list . id + '` WHERE `email`=? AND `cid`<>? AND `status`=' + Status . SUBSCRIBED + ' LIMIT 1' ;
2016-12-07 14:21:22 +00:00
let args = [ emailNew , cid ] ;
connection . query ( query , args , ( err , rows ) => {
connection . release ( ) ;
if ( err ) {
return callback ( err ) ;
}
2017-05-03 19:46:49 +00:00
if ( rows && rows . length > 0 ) {
return callback ( null , old , false ) ;
} else {
return callback ( null , old , true ) ;
2016-12-07 14:21:22 +00:00
}
} ) ;
2016-12-07 14:12:26 +00:00
} ) ;
} ) ;
} ) ;
} ;
2017-04-30 14:51:47 +00:00
2017-05-03 19:46:49 +00:00
/ *
Updates address in subscription _ _xxx
* /
module . exports . updateAddress = ( listId , subscriptionId , emailNew , callback ) => {
// update email address instead of adding new
2017-04-30 14:51:47 +00:00
db . getConnection ( ( err , connection ) => {
if ( err ) {
return callback ( err ) ;
}
2017-05-03 19:46:49 +00:00
connection . beginTransaction ( err => {
2017-04-30 14:51:47 +00:00
if ( err ) {
2017-05-03 19:46:49 +00:00
connection . release ( ) ;
2017-04-30 17:01:22 +00:00
return callback ( err ) ;
2017-04-30 14:51:47 +00:00
}
2017-05-04 21:42:46 +00:00
let query = 'SELECT `id` FROM `subscription__' + listId + '` WHERE `email`=? AND `id`<>? AND `status`=' + Status . SUBSCRIBED + ' LIMIT 1' ;
2017-05-03 19:46:49 +00:00
let args = [ emailNew , subscriptionId ] ;
connection . query ( query , args , ( err , rows ) => {
2017-04-30 14:51:47 +00:00
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2017-04-30 14:51:47 +00:00
}
2017-05-03 19:46:49 +00:00
if ( rows && rows . length > 0 ) {
2017-05-04 21:42:46 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( new Error ( _ ( 'Email address already registered' ) ) ) ) ;
2017-04-30 17:01:22 +00:00
}
2017-04-30 14:51:47 +00:00
2017-05-03 19:46:49 +00:00
let query = 'DELETE FROM `subscription__' + listId + '` WHERE `email`=? AND `id`<>?' ;
let args = [ emailNew , subscriptionId ] ;
2017-05-06 10:35:32 +00:00
connection . query ( query , args , err => {
2017-05-03 19:46:49 +00:00
if ( err ) {
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
}
2017-04-30 14:51:47 +00:00
2017-05-04 21:42:46 +00:00
let query = 'UPDATE `subscription__' + listId + '` SET `email`=? WHERE `id`=? AND `status`=' + Status . SUBSCRIBED + ' LIMIT 1' ;
2017-05-03 19:46:49 +00:00
let args = [ emailNew , subscriptionId ] ;
2017-05-04 21:42:46 +00:00
connection . query ( query , args , ( err , result ) => {
2017-04-30 14:51:47 +00:00
if ( err ) {
2017-05-03 19:46:49 +00:00
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
2017-04-30 14:51:47 +00:00
}
2017-04-30 17:01:22 +00:00
2017-05-04 21:42:46 +00:00
if ( ! result || ! result . affectedRows ) {
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( new Error ( _ ( 'Subscription not found in this list' ) ) ) ) ;
}
2017-05-03 19:46:49 +00:00
return connection . commit ( err => {
if ( err ) {
return helpers . rollbackAndReleaseConnection ( connection , ( ) => callback ( err ) ) ;
}
connection . release ( ) ;
2017-04-30 17:01:22 +00:00
2017-05-03 19:46:49 +00:00
return callback ( ) ;
} ) ;
} ) ;
2017-04-30 14:51:47 +00:00
} ) ;
} ) ;
} ) ;
} ) ;
2017-05-03 19:46:49 +00:00
} ;
2017-04-30 14:51:47 +00:00
2017-05-06 10:35:32 +00:00
module . exports . getUnsubscriptionMode = ( list , subscriptionId ) => list . unsubscriptionMode ; // eslint-disable-line no-unused-vars
// TODO: Once the unsubscription mode is customizable per segment, then this will be a good place to process it.