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.STRING,
141 defaultValue: 'Default Pause'
147 type: DataTypes.INTEGER,
151 type: DataTypes.INTEGER,
155 type: DataTypes.INTEGER,
158 phoneBarAutoAnswer: {
159 type: DataTypes.BOOLEAN,
162 phoneBarEnableSettings: {
163 type: DataTypes.BOOLEAN,
166 phoneBarUnconditionalNumber: {
167 type: DataTypes.STRING,
169 if (this.getDataValue('phoneBarUnconditional')) {
170 return this.getDataValue('phoneBarUnconditionalNumber');
175 phoneBarNoReplyNumber: {
176 type: DataTypes.STRING,
178 if (this.getDataValue('phoneBarNoReply')) {
179 return this.getDataValue('phoneBarNoReplyNumber');
184 phoneBarBusyNumber: {
185 type: DataTypes.STRING,
187 if (this.getDataValue('phoneBarBusy')) {
188 return this.getDataValue('phoneBarBusyNumber');
193 phoneBarUnconditional: {
194 type: DataTypes.BOOLEAN,
198 type: DataTypes.BOOLEAN,
202 type: DataTypes.BOOLEAN,
205 phoneBarListenPort: {
206 type: DataTypes.INTEGER(5),
210 type: DataTypes.INTEGER(5),
214 type: DataTypes.INTEGER(5),
217 phoneBarNameServer: {
218 type: DataTypes.STRING,
221 phoneBarStunServer: {
222 type: DataTypes.STRING,
225 phoneBarVADEnabled: {
226 type: DataTypes.BOOLEAN,
230 type: DataTypes.BOOLEAN,
234 type: DataTypes.BOOLEAN,
238 type: DataTypes.INTEGER(5),
241 phoneBarPublishEnabled: {
242 type: DataTypes.BOOLEAN,
246 type: DataTypes.BOOLEAN,
250 type: DataTypes.STRING,
253 ipaddr: { //REALTIME ASTERISK
254 type: DataTypes.STRING,
257 port: { //REALTIME ASTERISK
258 type: DataTypes.INTEGER(5),
261 regseconds: { //REALTIME ASTERISK
262 type: DataTypes.INTEGER(11),
265 fullcontact: { //REALTIME ASTERISK
266 type: DataTypes.STRING,
269 regserver: { //REALTIME ASTERISK
270 type: DataTypes.STRING,
273 useragent: { //REALTIME ASTERISK
274 type: DataTypes.STRING,
277 lastms: { //REALTIME ASTERISK
278 type: DataTypes.INTEGER(11),
282 type: DataTypes.ENUM('friend', 'user', 'peer'),
284 defaultValue: 'friend'
287 type: DataTypes.STRING,
289 defaultValue: 'from-sip'
292 type: DataTypes.ENUM('ALLOWED_NOT_SCREENED',
293 'ALLOWED_PASSED_SCREEN', 'ALLOWED_FAILED_SCREEN', 'ALLOWED',
294 'PROHIB_NOT_SCREENED', 'PROHIB_PASSED_SCREEN',
295 'PROHIB_FAILED_SCREEN', 'PROHIB'),
299 type: DataTypes.STRING,
303 type: DataTypes.STRING,
307 type: DataTypes.STRING,
311 type: DataTypes.STRING,
315 type: DataTypes.STRING,
319 type: DataTypes.STRING,
324 type: DataTypes.ENUM('rfc2833', 'info', 'shortinfo', 'inband',
327 defaultValue: 'rfc2833'
330 type: DataTypes.ENUM('yes', 'no', 'nonat', 'update', 'outgoing'),
335 type: DataTypes.ENUM('yes', 'no'),
340 type: DataTypes.STRING,
344 type: DataTypes.STRING,
348 type: DataTypes.STRING,
350 defaultValue: 'force_rport,comedia'
353 type: DataTypes.STRING,
356 namedcallgroup: { //We are in named call groups engineering,sales,netgroup,protgroup
357 type: DataTypes.STRING,
361 type: DataTypes.STRING,
364 namedpickupgroup: { //We can do call pick-p for named call group sales
365 type: DataTypes.STRING,
369 type: DataTypes.STRING,
374 type: DataTypes.STRING,
378 type: DataTypes.STRING,
380 defaultValue: 'alaw;ulaw;gsm'
383 type: DataTypes.STRING,
388 type: DataTypes.ENUM('yes', 'no'),
392 type: DataTypes.STRING,
394 defaultValue: 'port,invite'
397 type: DataTypes.ENUM('yes', 'no'),
402 type: DataTypes.ENUM('yes', 'no'),
407 type: DataTypes.ENUM('yes', 'no', 'never'),
411 type: DataTypes.ENUM('yes', 'no'),
415 type: DataTypes.ENUM('yes', 'no'),
419 type: DataTypes.INTEGER(11),
423 type: DataTypes.STRING,
427 type: DataTypes.STRING,
429 defaultValue: '"" <>'
432 type: DataTypes.STRING,
436 type: DataTypes.ENUM('yes', 'no'),
441 type: DataTypes.INTEGER(11),
445 type: DataTypes.ENUM('yes', 'no'),
449 type: DataTypes.ENUM('yes', 'no'),
453 type: DataTypes.ENUM('yes', 'no'),
457 type: DataTypes.ENUM('yes', 'no'),
461 type: DataTypes.STRING,
465 type: DataTypes.STRING,
469 type: DataTypes.ENUM('yes', 'no', 'always'),
474 type: DataTypes.INTEGER(11),
478 type: DataTypes.ENUM('yes', 'no'),
482 type: DataTypes.STRING,
486 type: DataTypes.ENUM('accept', 'refuse', 'originate'),
490 type: DataTypes.INTEGER(11),
494 type: DataTypes.INTEGER(11),
498 type: DataTypes.ENUM('uac', 'uas'),
502 t38pt_usertpsource: {
503 type: DataTypes.STRING,
507 type: DataTypes.STRING,
511 type: DataTypes.STRING,
515 type: DataTypes.STRING,
519 type: DataTypes.STRING,
521 defaultValue: 'dynamic'
524 type: DataTypes.ENUM('yes', 'no'),
529 type: DataTypes.INTEGER(11),
533 type: DataTypes.STRING,
537 type: DataTypes.STRING,
540 rtptimeout: { // Terminate call if 60 seconds of no RTP or RTCP activity on the audio channel when we're not on hold.
541 type: DataTypes.INTEGER(11),
544 rtpholdtimeout: { // Terminate call if 300 seconds of no RTP or RTCP activity on the audio channel when we're on hold (must be > rtptimeout)
545 type: DataTypes.INTEGER(11),
548 rtpkeepalive: { // Send keepalives in the RTP stream to keep NAT open (default is off - zero)
549 type: DataTypes.INTEGER(11),
553 type: DataTypes.ENUM('yes', 'no'),
558 type: DataTypes.STRING,
562 type: DataTypes.STRING,
566 type: DataTypes.INTEGER(11),
570 type: DataTypes.INTEGER(11),
574 type: DataTypes.INTEGER(11),
578 type: DataTypes.STRING,
582 type: DataTypes.STRING,
586 type: DataTypes.STRING,
589 unsolicited_mailbox: {
590 type: DataTypes.STRING,
594 type: DataTypes.STRING,
598 type: DataTypes.INTEGER(11),
602 type: DataTypes.ENUM('yes', 'no'),
607 type: DataTypes.ENUM('yes', 'no'),
611 type: DataTypes.ENUM('yes', 'no'),
615 type: DataTypes.ENUM('yes', 'no'),
619 type: DataTypes.ENUM('yes', 'no'),
623 type: DataTypes.ENUM('yes', 'no', 'fingerprint', 'certificate'),
627 type: DataTypes.INTEGER(11),
631 type: DataTypes.STRING,
635 type: DataTypes.STRING,
639 type: DataTypes.STRING,
643 type: DataTypes.STRING,
647 type: DataTypes.STRING,
651 type: DataTypes.ENUM('active', 'passive', 'actpass'),
655 type: DataTypes.STRING,
658 usereqphone: { //This provider requires ";user=phone" on URI
659 type: DataTypes.ENUM('yes', 'no'),
663 recordonfeature: { //Feature to use when INFO with Record: on is received.
664 type: DataTypes.STRING,
667 recordofffeature: { //Feature to use when INFO with Record: off is received.
668 type: DataTypes.STRING,
672 type: DataTypes.INTEGER(11),
676 registertrying: { //Send a 100 Trying when the device registers.
677 type: DataTypes.ENUM('yes', 'no'),
680 subscribemwi: { //Only send notifications if this phone subscribes for mailbox notification
681 type: DataTypes.ENUM('yes', 'no'),
684 vmexten: { // dialplan extension to reach mailbox. defaults to global vmexten which defaults to "asterisk"
685 type: DataTypes.STRING,
688 mohinterpret: { // This option specifies a preference for which music on hold class this channel should listen to when put on hold
689 type: DataTypes.STRING,
692 mohsuggest: { // This option specifies which music on hold class to suggest to the peer channel when this channel places the peer on hold.
693 type: DataTypes.STRING,
697 type: DataTypes.STRING,
701 type: DataTypes.ENUM('yes', 'no', 'nonat', 'update', 'update,nonat'),
709 * Authenticate - check if the passwords are the same
711 * @param {String} plainText
712 * {function} callBack
715 authenticate: function(plainText) {
716 return this.encryptPassword(plainText) === this.password;
724 makeSalt: function() {
725 return crypto.randomBytes(16).toString('base64');
730 * @param {String} password
734 encryptPassword: function(password) {
735 if (!password || !this.salt) return '';
736 var salt = new Buffer(this.salt, 'base64');
737 return crypto.pbkdf2Sync(password, salt, 10000, 64).toString(
743 * @param {String} password
747 md5Password: function(password) {
748 if (!password) return '';
749 return md5(password);
752 associate: function(models) {
754 User.hasMany(models.ChatMessage);
755 User.hasMany(models.MailMessage);
756 User.hasMany(models.Contact);
757 User.hasMany(models.Action);
758 User.belongsToMany(models.Module, {
759 through: 'user_has_modules'
761 User.belongsToMany(models.Channel, {
762 through: 'user_has_channels'
764 User.belongsToMany(models.MailRoom, {
765 through: 'user_has_mail_rooms'
767 User.belongsToMany(models.Team, {
768 through: models.UserHasTeam
770 User.belongsToMany(models.ChatRoom, {
771 through: models.UserHasChatRoom
773 User.belongsToMany(models.MailQueue, {
774 through: models.UserHasMailQueue,
777 User.belongsToMany(models.FaxQueue, {
778 through: models.UserHasFaxQueue,
781 User.belongsToMany(models.ChatQueue, {
782 through: models.UserHasChatQueue,
785 User.belongsToMany(models.VoiceQueue, {
786 through: models.UserHasVoiceQueue,
789 User.belongsToMany(models.List, {
790 through: models.UserHasList
792 User.hasMany(models.VoiceExtension, {
793 foreignKey: 'UserId',
794 as: 'UserExtensions',
800 User.addScope('user', {
803 $in: ['admin', 'user']
807 User.addScope('queues', {
808 include: [models.VoiceQueue, models.ChatQueue, models.MailQueue, models.FaxQueue]
810 User.addScope('telephone', {
815 User.addScope('checkPauseStatus', function(query) {
819 if (query.voicePause) {
820 scope.where.voicePause = (query.voicePause === 'true') ? true : false;
821 delete query.voicePause;
822 } else if (query.faxPause) {
823 scope.where.faxPause = (query.faxPause === 'true') ? true : false;
824 delete query.faxPause;
825 } else if (query.chatPause) {
826 scope.where.chatPause = (query.chatPause === 'true') ? true : false;
827 delete query.chatPause;
828 } else if (query.mailPause) {
829 scope.where.mailPause = (query.mailPause === 'true') ? true : false;
830 delete query.mailPause;
834 User.addScope('checkOnlineStatus', function(query) {
839 scope.where.online = (query.online === 'true') ? true : false;
844 User.addScope('checkSipStatus', function(query) {
849 scope.where.status = query.status;
854 User.addScope('checkQueueStatus', function(query) {
858 if (query.queueStatus) {
859 scope.where.queueStatus = query.queueStatus;
860 delete query.queueStatus;
864 User.addScope('agent', {
884 'phoneBarAutoAnswer',
885 'phoneBarEnableSettings',
886 'phoneBarUnconditional',
889 'phoneBarUnconditionalNumber',
890 'phoneBarNoReplyNumber',
891 'phoneBarBusyNumber',
892 'phoneBarListenPort',