3 var crypto = require('crypto');
4 var md5 = require('md5');
5 var _ = require('lodash');
6 var moment = require('moment');
7 var VoiceQueue = require('.').VoiceQueue;
9 module.exports = function(sequelize, DataTypes) {
10 var User = sequelize.define('User', {
12 type: DataTypes.STRING,
16 is: /^[A-Za-z0-9\.\_]+$/i
19 this.setDataValue('name', name);
20 this.setDataValue('defaultuser', name);
24 type: DataTypes.STRING,
28 type: DataTypes.STRING,
31 set: function(email) {
33 this.setDataValue('email', email.toLowerCase());
39 type: DataTypes.ENUM('admin', 'user', 'agent', 'telephone')
42 type: DataTypes.STRING,
47 set: function(password) {
48 this.salt = this.makeSalt();
49 this.setDataValue('password', this.encryptPassword(password));
50 this.setDataValue('md5secret', this.md5Password(this.name + ':asterisk:' + password));
54 type: DataTypes.STRING,
58 type: DataTypes.INTEGER(11),
60 set: function(internal) {
61 this.setDataValue('internal', internal);
62 this.setDataValue('accountcode', internal);
66 type: DataTypes.STRING
69 type: DataTypes.STRING
72 type: DataTypes.STRING
75 type: DataTypes.STRING
78 type: DataTypes.STRING
81 type: DataTypes.STRING
84 type: DataTypes.STRING
87 type: DataTypes.STRING
90 type: DataTypes.BOOLEAN,
97 type: DataTypes.STRING,
98 defaultValue: 'UNKNOWN'
104 type: DataTypes.STRING,
105 defaultValue: 'complete'
111 type: DataTypes.STRING
114 type: DataTypes.BOOLEAN,
116 set: function(voicePause) {
117 this.setDataValue('voicePause', voicePause);
119 this.setDataValue('queueStatus', 'paused');
120 this.setDataValue('queueStatusAt', moment().format("YYYY-MM-DD HH:mm:ss"));
122 this.setDataValue('queueStatus', 'complete');
123 this.setDataValue('queueStatusAt', moment().format("YYYY-MM-DD HH:mm:ss"));
128 type: DataTypes.BOOLEAN,
132 type: DataTypes.BOOLEAN,
136 type: DataTypes.BOOLEAN,
140 type: DataTypes.BOOLEAN,
144 type: DataTypes.STRING,
145 defaultValue: 'Default Pause'
151 type: DataTypes.INTEGER,
155 type: DataTypes.INTEGER,
159 type: DataTypes.INTEGER,
163 type: DataTypes.INTEGER,
166 phoneBarAutoAnswer: {
167 type: DataTypes.BOOLEAN,
170 phoneBarEnableSettings: {
171 type: DataTypes.BOOLEAN,
174 phoneBarUnconditionalNumber: {
175 type: DataTypes.STRING,
177 if (this.getDataValue('phoneBarUnconditional')) {
178 return this.getDataValue('phoneBarUnconditionalNumber');
183 phoneBarNoReplyNumber: {
184 type: DataTypes.STRING,
186 if (this.getDataValue('phoneBarNoReply')) {
187 return this.getDataValue('phoneBarNoReplyNumber');
192 phoneBarBusyNumber: {
193 type: DataTypes.STRING,
195 if (this.getDataValue('phoneBarBusy')) {
196 return this.getDataValue('phoneBarBusyNumber');
201 phoneBarUnconditional: {
202 type: DataTypes.BOOLEAN,
206 type: DataTypes.BOOLEAN,
210 type: DataTypes.BOOLEAN,
213 phoneBarListenPort: {
214 type: DataTypes.INTEGER(5),
218 type: DataTypes.INTEGER(5),
222 type: DataTypes.INTEGER(5),
225 phoneBarNameServer: {
226 type: DataTypes.STRING,
229 phoneBarStunServer: {
230 type: DataTypes.STRING,
233 phoneBarVADEnabled: {
234 type: DataTypes.BOOLEAN,
238 type: DataTypes.BOOLEAN,
242 type: DataTypes.BOOLEAN,
246 type: DataTypes.INTEGER(5),
249 phoneBarPublishEnabled: {
250 type: DataTypes.BOOLEAN,
254 type: DataTypes.BOOLEAN,
258 type: DataTypes.STRING,
261 ipaddr: { //REALTIME ASTERISK
262 type: DataTypes.STRING,
265 port: { //REALTIME ASTERISK
266 type: DataTypes.INTEGER(5),
269 regseconds: { //REALTIME ASTERISK
270 type: DataTypes.INTEGER(11),
273 fullcontact: { //REALTIME ASTERISK
274 type: DataTypes.STRING,
277 regserver: { //REALTIME ASTERISK
278 type: DataTypes.STRING,
281 useragent: { //REALTIME ASTERISK
282 type: DataTypes.STRING,
285 lastms: { //REALTIME ASTERISK
286 type: DataTypes.INTEGER(11),
290 type: DataTypes.ENUM('friend', 'user', 'peer'),
292 defaultValue: 'friend'
295 type: DataTypes.STRING,
297 defaultValue: 'from-sip'
300 type: DataTypes.ENUM('ALLOWED_NOT_SCREENED',
301 'ALLOWED_PASSED_SCREEN', 'ALLOWED_FAILED_SCREEN', 'ALLOWED',
302 'PROHIB_NOT_SCREENED', 'PROHIB_PASSED_SCREEN',
303 'PROHIB_FAILED_SCREEN', 'PROHIB'),
307 type: DataTypes.STRING,
311 type: DataTypes.STRING,
315 type: DataTypes.STRING,
319 type: DataTypes.STRING,
323 type: DataTypes.STRING,
327 type: DataTypes.STRING,
332 type: DataTypes.ENUM('rfc2833', 'info', 'shortinfo', 'inband',
335 defaultValue: 'rfc2833'
338 type: DataTypes.ENUM('yes', 'no', 'nonat', 'update', 'outgoing'),
343 type: DataTypes.ENUM('yes', 'no'),
348 type: DataTypes.STRING,
352 type: DataTypes.STRING,
356 type: DataTypes.STRING,
358 defaultValue: 'force_rport,comedia'
361 type: DataTypes.STRING,
364 namedcallgroup: { //We are in named call groups engineering,sales,netgroup,protgroup
365 type: DataTypes.STRING,
369 type: DataTypes.STRING,
372 namedpickupgroup: { //We can do call pick-p for named call group sales
373 type: DataTypes.STRING,
377 type: DataTypes.STRING,
382 type: DataTypes.STRING,
386 type: DataTypes.STRING,
388 defaultValue: 'alaw;ulaw;gsm'
391 type: DataTypes.STRING,
396 type: DataTypes.ENUM('yes', 'no'),
400 type: DataTypes.STRING,
402 defaultValue: 'port,invite'
405 type: DataTypes.ENUM('yes', 'no'),
410 type: DataTypes.ENUM('yes', 'no'),
415 type: DataTypes.ENUM('yes', 'no', 'never'),
419 type: DataTypes.ENUM('yes', 'no'),
423 type: DataTypes.ENUM('yes', 'no'),
427 type: DataTypes.INTEGER(11),
431 type: DataTypes.STRING,
435 type: DataTypes.STRING,
437 defaultValue: '"" <>'
440 type: DataTypes.STRING,
444 type: DataTypes.ENUM('yes', 'no'),
449 type: DataTypes.INTEGER(11),
453 type: DataTypes.ENUM('yes', 'no'),
457 type: DataTypes.ENUM('yes', 'no'),
461 type: DataTypes.ENUM('yes', 'no'),
465 type: DataTypes.ENUM('yes', 'no'),
469 type: DataTypes.STRING,
473 type: DataTypes.STRING,
477 type: DataTypes.ENUM('yes', 'no', 'always'),
482 type: DataTypes.INTEGER(11),
486 type: DataTypes.ENUM('yes', 'no'),
490 type: DataTypes.STRING,
494 type: DataTypes.ENUM('accept', 'refuse', 'originate'),
498 type: DataTypes.INTEGER(11),
502 type: DataTypes.INTEGER(11),
506 type: DataTypes.ENUM('uac', 'uas'),
510 t38pt_usertpsource: {
511 type: DataTypes.STRING,
515 type: DataTypes.STRING,
519 type: DataTypes.STRING,
523 type: DataTypes.STRING,
527 type: DataTypes.STRING,
529 defaultValue: 'dynamic'
532 type: DataTypes.ENUM('yes', 'no'),
537 type: DataTypes.INTEGER(11),
541 type: DataTypes.STRING,
545 type: DataTypes.STRING,
548 rtptimeout: { // Terminate call if 60 seconds of no RTP or RTCP activity on the audio channel when we're not on hold.
549 type: DataTypes.INTEGER(11),
552 rtpholdtimeout: { // Terminate call if 300 seconds of no RTP or RTCP activity on the audio channel when we're on hold (must be > rtptimeout)
553 type: DataTypes.INTEGER(11),
556 rtpkeepalive: { // Send keepalives in the RTP stream to keep NAT open (default is off - zero)
557 type: DataTypes.INTEGER(11),
561 type: DataTypes.ENUM('yes', 'no'),
566 type: DataTypes.STRING,
570 type: DataTypes.STRING,
574 type: DataTypes.INTEGER(11),
578 type: DataTypes.INTEGER(11),
582 type: DataTypes.INTEGER(11),
586 type: DataTypes.STRING,
590 type: DataTypes.STRING,
594 type: DataTypes.STRING,
597 unsolicited_mailbox: {
598 type: DataTypes.STRING,
602 type: DataTypes.STRING,
606 type: DataTypes.INTEGER(11),
610 type: DataTypes.ENUM('yes', 'no'),
615 type: DataTypes.ENUM('yes', 'no'),
619 type: DataTypes.ENUM('yes', 'no'),
623 type: DataTypes.ENUM('yes', 'no'),
627 type: DataTypes.ENUM('yes', 'no'),
631 type: DataTypes.ENUM('yes', 'no', 'fingerprint', 'certificate'),
635 type: DataTypes.INTEGER(11),
639 type: DataTypes.STRING,
643 type: DataTypes.STRING,
647 type: DataTypes.STRING,
651 type: DataTypes.STRING,
655 type: DataTypes.STRING,
659 type: DataTypes.ENUM('active', 'passive', 'actpass'),
663 type: DataTypes.STRING,
666 usereqphone: { //This provider requires ";user=phone" on URI
667 type: DataTypes.ENUM('yes', 'no'),
671 recordonfeature: { //Feature to use when INFO with Record: on is received.
672 type: DataTypes.STRING,
675 recordofffeature: { //Feature to use when INFO with Record: off is received.
676 type: DataTypes.STRING,
680 type: DataTypes.INTEGER(11),
684 registertrying: { //Send a 100 Trying when the device registers.
685 type: DataTypes.ENUM('yes', 'no'),
688 subscribemwi: { //Only send notifications if this phone subscribes for mailbox notification
689 type: DataTypes.ENUM('yes', 'no'),
692 vmexten: { // dialplan extension to reach mailbox. defaults to global vmexten which defaults to "asterisk"
693 type: DataTypes.STRING,
696 mohinterpret: { // This option specifies a preference for which music on hold class this channel should listen to when put on hold
697 type: DataTypes.STRING,
700 mohsuggest: { // This option specifies which music on hold class to suggest to the peer channel when this channel places the peer on hold.
701 type: DataTypes.STRING,
705 type: DataTypes.STRING,
709 type: DataTypes.ENUM('yes', 'no', 'nonat', 'update', 'update,nonat'),
717 * Authenticate - check if the passwords are the same
719 * @param {String} plainText
720 * {function} callBack
723 authenticate: function(plainText) {
724 return this.encryptPassword(plainText) === this.password;
732 makeSalt: function() {
733 return crypto.randomBytes(16).toString('base64');
738 * @param {String} password
742 encryptPassword: function(password) {
743 if (!password || !this.salt) return '';
744 var salt = new Buffer(this.salt, 'base64');
745 return crypto.pbkdf2Sync(password, salt, 10000, 64).toString(
751 * @param {String} password
755 md5Password: function(password) {
756 if (!password) return '';
757 return md5(password);
760 associate: function(models) {
762 User.hasMany(models.ChatMessage);
763 User.hasMany(models.MailMessage);
764 User.hasMany(models.Contact);
765 User.hasMany(models.Action);
766 User.belongsToMany(models.Module, {
767 through: 'user_has_modules'
769 User.belongsToMany(models.Channel, {
770 through: 'user_has_channels'
772 User.belongsToMany(models.MailRoom, {
773 through: 'user_has_mail_rooms'
775 User.belongsToMany(models.Team, {
776 through: models.UserHasTeam
778 User.belongsToMany(models.ChatRoom, {
779 through: models.UserHasChatRoom
781 User.belongsToMany(models.MailQueue, {
782 through: models.UserHasMailQueue,
785 User.belongsToMany(models.FaxQueue, {
786 through: models.UserHasFaxQueue,
789 User.belongsToMany(models.ChatQueue, {
790 through: models.UserHasChatQueue,
793 User.belongsToMany(models.VoiceQueue, {
794 through: models.UserHasVoiceQueue,
797 User.belongsToMany(models.List, {
798 through: models.UserHasList
800 User.hasMany(models.VoiceExtension, {
801 foreignKey: 'UserId',
802 as: 'UserExtensions',
808 User.addScope('user', {
811 $in: ['admin', 'user']
815 User.addScope('queues', {
816 include: [models.VoiceQueue, models.ChatQueue, models.MailQueue, models.FaxQueue]
818 User.addScope('telephone', {
823 User.addScope('checkPauseStatus', function(query) {
827 if (query.voicePause) {
828 scope.where.voicePause = (query.voicePause === 'true') ? true : false;
829 delete query.voicePause;
830 } else if (query.faxPause) {
831 scope.where.faxPause = (query.faxPause === 'true') ? true : false;
832 delete query.faxPause;
833 } else if (query.chatPause) {
834 scope.where.chatPause = (query.chatPause === 'true') ? true : false;
835 delete query.chatPause;
836 } else if (query.mailPause) {
837 scope.where.mailPause = (query.mailPause === 'true') ? true : false;
838 delete query.mailPause;
842 User.addScope('checkOnlineStatus', function(query) {
847 scope.where.online = (query.online === 'true') ? true : false;
852 User.addScope('checkSipStatus', function(query) {
857 scope.where.status = query.status;
862 User.addScope('checkQueueStatus', function(query) {
866 if (query.queueStatus) {
867 scope.where.queueStatus = query.queueStatus;
868 delete query.queueStatus;
872 User.addScope('agent', {
892 'phoneBarAutoAnswer',
893 'phoneBarEnableSettings',
894 'phoneBarUnconditional',
897 'phoneBarUnconditionalNumber',
898 'phoneBarNoReplyNumber',
899 'phoneBarBusyNumber',
900 'phoneBarListenPort',