# xCALLY MOTION Changelog
+- * 0cbc254 - 2016-09-13: server side models interval + user
+- * 0c84ddb - 2016-09-13: sever side update tools + app.js
+- * f8ce2ee - 2016-09-13: automation chat update (server side - emitter)
+- * 7a3e5af - 2016-09-13: automation fax update (server side - emitter) automation mail update (server side - code clean)
+- * e49ba5d - 2016-09-13: automation mail update (server side - emitter)
+- * 22e90bb - 2016-09-13: Log removed
+- * 4b2abca - 2016-09-13: Added cluster emitter to agi service
- * 5daed3e - 2016-09-13: server side model cluster emitter
- * 448ae9a - 2016-09-13: server side config/ami update cluster emitter
- * a7fe2de - 2016-09-13: server side config/ami update
}
// Start Cally Square Projects
- require('./config/automations/mail')(); // andre
- require('./config/automations/fax')(); // andre
- require('./config/automations/chat')(); // andre
+ require('./config/automations/mail')();
+ require('./config/automations/fax')();
+ require('./config/automations/chat')();
require('./config/triggers')(ami); // max
require('./config/ami')(ami); // dani
require('./config/scheduler')(); // max
var cp = require('child_process');
var util = require('util');
var models = require('../../models');
+var emitter = require('cluster-emitter');
module.exports = function() {
var child = cp
function synchCollection(data, child) {
var condition = {};
- models[data.model].afterCreate(function(doc) {
+ emitter.on(data.model + '.afterCreate', function(doc) {
condition[data.key] = doc[data.key];
child.send({
message: 'updateCollection',
doc: doc
});
});
- models[data.model].afterUpdate(function(doc) {
+ emitter.on(data.model + '.afterUpdate', function(doc) {
condition[data.key] = doc[data.key];
child.send({
message: 'updateCollection',
doc: doc
});
});
- models[data.model].afterDestroy(function(doc) {
+ emitter.on(data.model + '.afterDestroy', function(doc) {
condition[data.key] = doc[data.key];
child.send({
message: 'removeFromCollection',
});
}
+// function synchCollection(data, child) {
+// var condition = {};
+// models[data.model].afterCreate(function(doc) {
+// condition[data.key] = doc[data.key];
+// child.send({
+// message: 'updateCollection',
+// collection: data.collection,
+// condition: condition,
+// doc: doc
+// });
+// });
+// models[data.model].afterUpdate(function(doc) {
+// condition[data.key] = doc[data.key];
+// child.send({
+// message: 'updateCollection',
+// collection: data.collection,
+// condition: condition,
+// doc: doc
+// });
+// });
+// models[data.model].afterDestroy(function(doc) {
+// condition[data.key] = doc[data.key];
+// child.send({
+// message: 'removeFromCollection',
+// collection: data.collection,
+// condition: condition
+// });
+// });
+// }
+
function replaceCollection(data, child) {
- var condition = {};
- models[data.model].afterCreate(function(doc) {
+ emitter.on(data.model + '.afterCreate', function(doc) {
getCollection(data, child, doc);
});
- models[data.model].afterUpdate(function(doc) {
+ emitter.on(data.model + '.afterUpdate', function(doc) {
getCollection(data, child, doc);
});
- models[data.model].afterDestroy(function(doc) {
+ emitter.on(data.model + '.afterDestroy', function(doc) {
getCollection(data, child, doc);
});
}
+// function replaceCollection(data, child) {
+// models[data.model].afterCreate(function(doc) {
+// getCollection(data, child, doc);
+// });
+// models[data.model].afterUpdate(function(doc) {
+// getCollection(data, child, doc);
+// });
+// models[data.model].afterDestroy(function(doc) {
+// getCollection(data, child, doc);
+// });
+// }
+
function getCollection(data, child, doc) {
models[data.model]
.findAll()
var _ = require('lodash');
var moment = require('moment');
+var emitter = require('cluster-emitter');
var Automation = require('../../models').Automation;
var ChatRoom = require('../../models').ChatRoom;
-var automationTimeout;
var activeChatAutomations = {};
function executeAutomation(id) {
- console.log('Executing Chat Automation ', id);
+ console.log('[Automation] Executing Chat', id);
var _chatAutomation;
return Automation
.scope('all')
});
})
.catch(function(err) {
- console.log('Chat Automation exec error', err);
+ console.error('[Automation] Error in Chat exec');
+ console.error('[Automation] Message:', err.message);
+ console.error('[Automation] Stack:', err.stack);
});
}
}
})
.catch(function(err) {
- console.log('Automatic chat status error', err);
+ console.error('[Automation] Error in Mail setStatus');
+ console.error('[Automation] Message:', err.message);
+ console.error('[Automation] Stack:', err.stack);
});
}
}
function createInterval(chatAutomation) {
- console.log('Chat Automation ', chatAutomation.id, ' set with timeout ', chatAutomation.timeout * 60 * 1000);
+ console.log('[Automation] Mail', chatAutomation.id, 'set with timeout', chatAutomation.timeout * 60 * 1000);
activeChatAutomations['interval' + chatAutomation.id] = setInterval(function() {
executeAutomation(chatAutomation.id);
}, chatAutomation.timeout * 60 * 1000);
module.exports = function() {
- Automation.afterCreate(function(doc, options) {
- console.log('Chat Automation ', doc.id, ' created, the status is ', doc.status);
- if (doc.status && doc.channel === 'chat') {
- createInterval(doc);
+ console.log('[Automation] Chat service started');
+
+ emitter.on('Automation.afterCreate', function(doc, options) {
+ if (doc.channel === 'chat') {
+ console.log('[Automation] Chat', doc.id, 'created, the status is', doc.status);
+ if (doc.status) {
+ createInterval(doc);
+ }
}
});
- Automation.afterUpdate(function(doc, options) {
- console.log('Chat Automation ', doc.id, ' updated, the status is ', doc.status);
- if (activeChatAutomations['interval' + doc.id]) {
- console.log('Chat automation unset ', doc.id);
- clearInterval(activeChatAutomations['interval' + doc.id]);
- delete activeChatAutomations['interval' + doc.id];
- }
- if (doc.status && doc.channel === 'chat') {
- createInterval(doc);
+ emitter.on('Automation.afterUpdate', function(doc, options) {
+ if (doc.channel === 'chat') {
+ console.log('[Automation] Chat', doc.id, 'updated, the status is', doc.status);
+ if (activeChatAutomations['interval' + doc.id]) {
+ console.log('[Automation] Chat unset ', doc.id);
+ clearInterval(activeChatAutomations['interval' + doc.id]);
+ delete activeChatAutomations['interval' + doc.id];
+ }
+ if (doc.status) {
+ createInterval(doc);
+ }
}
});
- Automation.afterDelete(function(doc, options) {
- console.log('Chat Automation ', doc.id, ' deleted');
- if (activeChatAutomations['interval' + doc.id]) {
- console.log('Chat automation unset ', doc.id);
- clearInterval(activeChatAutomations['interval' + doc.id]);
- delete activeChatAutomations['interval' + doc.id];
+ emitter.on('Automation.afterDelete', function(doc, options) {
+ if (doc.channel === 'chat') {
+ console.log('[Automation] Chat', doc.id, ' deleted');
+ if (activeChatAutomations['interval' + doc.id]) {
+ console.log('[Automation] Chat unset ', doc.id);
+ clearInterval(activeChatAutomations['interval' + doc.id]);
+ delete activeChatAutomations['interval' + doc.id];
+ }
}
});
})
.then(function(chatAutomations) {
+ console.log('[Automation] Chat are', chatAutomations.length);
+
chatAutomations.forEach(function(chatAutomation) {
createInterval(chatAutomation);
});
+
})
.catch(function(err) {
- console.log('Chat Automation init error', err);
+ console.error('[Automation] Error in Chat init');
+ console.error('[Automation] Message:', err.message);
+ console.error('[Automation] Stack:', err.stack);
});
};
'use strict';
var _ = require('lodash');
-var config = require('../environment');
var moment = require('moment');
-// var stringifyObject = require('stringify-object');
+var emitter = require('cluster-emitter');
-var sequelize = require('../../models').sequelize;
var Automation = require('../../models').Automation;
var FaxRoom = require('../../models').FaxRoom;
-var automationTimeout;
var activeFaxAutomations = {};
function executeAutomation(id) {
- console.log('Executing Mail Automation ', id);
+ console.log('[Automation] Executing Fax', id);
var _faxAutomation;
return Automation
.scope('all')
});
})
.catch(function(err) {
- console.log('Fax Automation exec error', err);
+ console.error('[Automation] Error in Fax exec');
+ console.error('[Automation] Message:', err.message);
+ console.error('[Automation] Stack:', err.stack);
});
}
}
})
.catch(function(err) {
- console.log('Automatic mail status error', err);
+ console.error('[Automation] Error in Fax setStatus');
+ console.error('[Automation] Message:', err.message);
+ console.error('[Automation] Stack:', err.stack);
});
}
}
function createInterval(faxAutomation) {
- console.log('Fax Automation ', faxAutomation.id, ' set with timeout ', faxAutomation.timeout * 60 * 1000);
+ console.log('[Automation] Mail', faxAutomation.id, 'set with timeout', faxAutomation.timeout * 60 * 1000);
activeFaxAutomations['interval' + faxAutomation.id] = setInterval(function() {
executeAutomation(faxAutomation.id);
}, faxAutomation.timeout * 60 * 1000);
module.exports = function() {
- Automation.afterCreate(function(doc, options) {
- console.log('Fax Automation ', doc.id, ' created, the status is ', doc.status);
- if (doc.status && doc.channel === 'fax') {
- createInterval(doc);
+ console.log('[Automation] Fax service started');
+
+ emitter.on('Automation.afterCreate', function(doc, options) {
+ if (doc.channel === 'fax') {
+ console.log('[Automation] Fax', doc.id, 'created, the status is', doc.status);
+ if (doc.status) {
+ createInterval(doc);
+ }
}
});
- Automation.afterUpdate(function(doc, options) {
- console.log('Fax Automation ', doc.id, ' updated, the status is ', doc.status);
- if (activeFaxAutomations['interval' + doc.id]) {
- console.log('Fax automation unset ', doc.id);
- clearInterval(activeFaxAutomations['interval' + doc.id]);
- delete activeFaxAutomations['interval' + doc.id];
- }
- if (doc.status && doc.channel === 'fax') {
- createInterval(doc);
+ emitter.on('Automation.afterUpdate', function(doc, options) {
+ if (doc.channel === 'fax') {
+ console.log('[Automation] Fax', doc.id, 'updated, the status is', doc.status);
+ if (activeFaxAutomations['interval' + doc.id]) {
+ console.log('[Automation] Fax unset ', doc.id);
+ clearInterval(activeFaxAutomations['interval' + doc.id]);
+ delete activeFaxAutomations['interval' + doc.id];
+ }
+ if (doc.status) {
+ createInterval(doc);
+ }
}
});
- Automation.afterDelete(function(doc, options) {
- console.log('Fax Automation ', doc.id, ' deleted');
- if (activeFaxAutomations['interval' + doc.id]) {
- console.log('Fax automation unset ', doc.id);
- clearInterval(activeFaxAutomations['interval' + doc.id]);
- delete activeFaxAutomations['interval' + doc.id];
+ emitter.on('Automation.afterDelete', function(doc, options) {
+ if (doc.channel === 'fax') {
+ console.log('[Automation] Fax', doc.id, ' deleted');
+ if (activeFaxAutomations['interval' + doc.id]) {
+ console.log('[Automation] Fax unset ', doc.id);
+ clearInterval(activeFaxAutomations['interval' + doc.id]);
+ delete activeFaxAutomations['interval' + doc.id];
+ }
}
});
})
.then(function(faxAutomations) {
+ console.log('[Automation] Fax are', faxAutomations.length);
+
faxAutomations.forEach(function(faxAutomation) {
createInterval(faxAutomation);
});
+
})
.catch(function(err) {
- console.log('Fax Automation init error', err);
+ console.error('[Automation] Error in Mail init');
+ console.error('[Automation] Message:', err.message);
+ console.error('[Automation] Stack:', err.stack);
});
};
'use strict';
var _ = require('lodash');
-var config = require('../environment');
var moment = require('moment');
-// var stringifyObject = require('stringify-object');
+var emitter = require('cluster-emitter');
-var sequelize = require('../../models').sequelize;
var Automation = require('../../models').Automation;
var MailRoom = require('../../models').MailRoom;
var activeMailAutomations = {};
function executeAutomation(id) {
- console.log('Executing Mail Automation ', id);
+ console.log('[Automation] Executing Mail', id);
var _mailAutomation;
return Automation
.scope('all')
});
})
.catch(function(err) {
- console.log('Mail Automation exec error', err);
+ console.error('[Automation] Error in Mail exec');
+ console.error('[Automation] Message:', err.message);
+ console.error('[Automation] Stack:', err.stack);
});
}
}
})
.catch(function(err) {
- console.log('Automatic mail status error', err);
+ console.error('[Automation] Error in Mail setStatus');
+ console.error('[Automation] Message:', err.message);
+ console.error('[Automation] Stack:', err.stack);
});
}
}
function createInterval(mailAutomation) {
- console.log('Mail Automation ', mailAutomation.id, ' set with timeout ', mailAutomation.timeout * 60 * 1000);
+ console.log('[Automation] Mail', mailAutomation.id, 'set with timeout', mailAutomation.timeout * 60 * 1000);
activeMailAutomations['interval' + mailAutomation.id] = setInterval(function() {
executeAutomation(mailAutomation.id);
}, mailAutomation.timeout * 60 * 1000);
module.exports = function() {
- Automation.afterCreate(function(doc, options) {
- console.log('Mail Automation ', doc.id, ' created, the status is ', doc.status);
- if (doc.status && doc.channel === 'mail') {
- createInterval(doc);
+ console.log('[Automation] Mail service started');
+
+ emitter.on('Automation.afterCreate', function(doc, options) {
+ if (doc.channel === 'mail') {
+ console.log('[Automation] Mail', doc.id, 'created, the status is', doc.status);
+ if (doc.status) {
+ createInterval(doc);
+ }
}
});
- Automation.afterUpdate(function(doc, options) {
- console.log('Mail Automation ', doc.id, ' updated, the status is ', doc.status);
- if (activeMailAutomations['interval' + doc.id]) {
- console.log('Mail automation unset ', doc.id);
- clearInterval(activeMailAutomations['interval' + doc.id]);
- delete activeMailAutomations['interval' + doc.id];
- }
- if (doc.status && doc.channel === 'mail') {
- createInterval(doc);
+ emitter.on('Automation.afterUpdate', function(doc, options) {
+ if (doc.channel === 'mail') {
+ console.log('[Automation] Mail', doc.id, 'updated, the status is', doc.status);
+ if (activeMailAutomations['interval' + doc.id]) {
+ console.log('[Automation] Mail unset ', doc.id);
+ clearInterval(activeMailAutomations['interval' + doc.id]);
+ delete activeMailAutomations['interval' + doc.id];
+ }
+ if (doc.status) {
+ createInterval(doc);
+ }
}
});
- Automation.afterDelete(function(doc, options) {
- console.log('Mail Automation ', doc.id, ' deleted');
- if (activeMailAutomations['interval' + doc.id]) {
- console.log('Mail automation unset ', doc.id);
- clearInterval(activeMailAutomations['interval' + doc.id]);
- delete activeMailAutomations['interval' + doc.id];
+ emitter.on('Automation.afterDelete', function(doc, options) {
+ if (doc.channel === 'mail') {
+ console.log('[Automation] Mail', doc.id, ' deleted');
+ if (activeMailAutomations['interval' + doc.id]) {
+ console.log('[Automation] Mail unset ', doc.id);
+ clearInterval(activeMailAutomations['interval' + doc.id]);
+ delete activeMailAutomations['interval' + doc.id];
+ }
}
});
})
.then(function(mailAutomations) {
+ console.log('[Automation] Mail are', mailAutomations.length);
+
mailAutomations.forEach(function(mailAutomation) {
createInterval(mailAutomation);
});
+
})
.catch(function(err) {
- console.log('Mail Automation init error', err);
+ console.error('[Automation] Error in Mail init');
+ console.error('[Automation] Message:', err.message);
+ console.error('[Automation] Stack:', err.stack);
});
};
/**
*
*/
+var emitter = require('cluster-emitter');
+
module.exports = function(sequelize, DataTypes) {
var MailServerOut = sequelize.define('MailServerOut', {
},
source: DataTypes.STRING
}, {
- tableName: 'mail_servers_out'
+ tableName: 'mail_servers_out',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('MailServerOut.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('MailServerOut.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('MailServerOut.afterDestroy', doc);
+ }
+ }
});
return MailServerOut;
'use strict';
+var emitter = require('cluster-emitter');
+
module.exports = function(sequelize, DataTypes) {
var SmsAccount = sequelize.define('SmsAccount', {
name: {
}
}, {
tableName: 'sms_accounts',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('SmsAccount.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('SmsAccount.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('SmsAccount.afterDestroy', doc);
+ }
+ },
associate: function(models) {
SmsAccount.hasMany(models.SmsRoom);
SmsAccount.hasMany(models.SmsApplication, {
'use strict';
+var emitter = require('cluster-emitter');
+
module.exports = function(sequelize, DataTypes) {
var SquareOdbc = sequelize.define('SquareOdbc', {
},
description: DataTypes.STRING
}, {
- tableName: 'square_odbc'
+ tableName: 'square_odbc',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('SquareOdbc.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('SquareOdbc.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('SquareOdbc.afterDestroy', doc);
+ }
+ }
});
return SquareOdbc;
'use strict';
+var emitter = require('cluster-emitter');
+
module.exports = function(sequelize, DataTypes) {
var SquareProject = sequelize.define('SquareProject', {
}
}, {
tableName: 'square_projects',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('SquareProject.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('SquareProject.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('SquareProject.afterDestroy', doc);
+ }
+ }
});
return SquareProject;
* Square recordings Model
*/
+var emitter = require('cluster-emitter');
+
+
var crypto = require('crypto');
module.exports = function(sequelize, DataTypes) {
filename: DataTypes.STRING,
savePath: DataTypes.STRING
}, {
- tableName: 'square_recordings'
+ tableName: 'square_recordings',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('SquareRecording.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('SquareRecording.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('SquareRecording.afterDestroy', doc);
+ }
+ }
});
return SquareRecording;
*/
var crypto = require('crypto');
+var emitter = require('cluster-emitter');
module.exports = function(sequelize, DataTypes) {
subject: DataTypes.STRING,
html: DataTypes.TEXT
}, {
- tableName: 'tools_templates'
+ tableName: 'tools_templates',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('Template.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('Template.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('Template.afterDestroy', doc);
+ }
+ }
});
return Template;
* Automation Model
*/
+var emitter = require('cluster-emitter');
+
module.exports = function(sequelize, DataTypes) {
var Automation = sequelize.define('Automation', {
}
}, {
tableName: 'tools_automations',
+ hooks: {
+ afterCreate: function(doc, options) {
+ emitter.to(['master']).emit('Automation.afterCreate', doc);
+ },
+ afterUpdate: function(doc, options) {
+ emitter.to(['master']).emit('Automation.afterUpdate', doc);
+ },
+ afterDelete: function(doc, options) {
+ emitter.to(['master']).emit('Automation.afterDelete', doc);
+ }
+ },
associate: function(models) {
Automation.hasMany(models.ToolsCondition, {
as: {
const emitter = require('cluster-emitter');
+var emitter = require('cluster-emitter');
+
module.exports = function(sequelize, DataTypes) {
var Interval = sequelize.define('Interval', {
name: {
}
}, {
tableName: 'tools_intervals',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('Interval.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('Interval.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('Interval.afterDestroy', doc);
+ }
+ },
associate: function(models) {
Interval.hasMany(models.Interval, {
as: 'SubIntervals',
'use strict';
+var emitter = require('cluster-emitter');
+
+
module.exports = function(sequelize, DataTypes) {
var Sound = sequelize.define('Sound', {
converted_bitRate: DataTypes.BIGINT,
converted_sampleRate: DataTypes.INTEGER
}, {
- tableName: 'tools_sounds'
+ tableName: 'tools_sounds',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('Sound.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('Sound.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('Sound.afterDestroy', doc);
+ }
+ }
});
return Sound;
'use strict';
+var emitter = require('cluster-emitter');
+
module.exports = function(sequelize, DataTypes) {
var Variable = sequelize.define('Variable', {
description: DataTypes.STRING
}, {
tableName: 'tools_variables',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('Variable.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('Variable.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('Variable.afterDestroy', doc);
+ }
+ },
associate: function(models) {
Variable.hasMany(models.ZendeskField);
Variable.hasMany(models.DeskField);
'use strict';
-const crypto = require('crypto');
-const md5 = require('md5');
-const _ = require('lodash');
-const moment = require('moment');
-const emitter = require('cluster-emitter');
-const VoiceQueue = require('.').VoiceQueue;
+var crypto = require('crypto');
+var md5 = require('md5');
+var _ = require('lodash');
+var moment = require('moment');
+var VoiceQueue = require('.').VoiceQueue;
+var emitter = require('cluster-emitter');
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
}
}, {
tableName: 'users',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('User.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('User.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('User.afterDestroy', doc);
+ }
+ },
instanceMethods: {
/**
* Authenticate - check if the passwords are the same
/* jshint indent: 2 */
+var emitter = require('cluster-emitter');
+
module.exports = function(sequelize, DataTypes) {
var VoiceQueue = sequelize.define('VoiceQueue', {
name: {
}
}, {
tableName: 'voice_queues',
+ hooks: {
+ afterCreate: function(doc) {
+ emitter.to(['master']).emit('VoiceQueue.afterCreate', doc);
+ },
+ afterUpdate: function(doc) {
+ emitter.to(['master']).emit('VoiceQueue.afterUpdate', doc);
+ },
+ afterDestroy: function(doc) {
+ emitter.to(['master']).emit('VoiceQueue.afterDestroy', doc);
+ }
+ },
associate: function(models) {
VoiceQueue.belongsToMany(models.User, {
through: models.UserHasVoiceQueue,