You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1332 lines
38 KiB

define(function(require) {
var $ = require('jquery'),
_ = require('lodash'),
monster = require('monster');
var app = {
requests: {
'callflows.device.getProvisionerPhones': {
'apiRoot': monster.config.api.provisioner,
'url': 'phones/',
'verb': 'GET',
'headers': {
'Accept': '*/*'
}
}
},
subscribe: {
'callflows.fetchActions': 'deviceDefineActions',
'callflows.device.popupEdit': 'devicePopupEdit',
'callflows.device.edit': '_deviceEdit'
},
devicePopupEdit: function(args) {
var self = this,
popup,
popup_html,
data = args.data,
callback = args.callback,
data_defaults = args.data_defaults;
popup_html = $('<div class="inline_popup callflows-port"><div class="inline_content main_content"/></div>');
self.deviceEdit(data, popup_html, $('.inline_content', popup_html), {
save_success: function(_data) {
popup.dialog('close');
if (typeof callback === 'function') {
callback(_data);
}
},
delete_success: function() {
popup.dialog('close');
if (typeof callback === 'function') {
callback({ data: {} });
}
},
after_render: function() {
popup = monster.ui.dialog(popup_html, {
title: (data.id) ? self.i18n.active().callflows.device.edit_device : self.i18n.active().callflows.device.create_device
});
}
}, data_defaults);
},
// Added for the subscribed event to avoid refactoring deviceEdit
_deviceEdit: function(args) {
var self = this;
self.deviceEdit(args.data, args.parent, args.target, args.callbacks, args.data_defaults);
},
deviceEdit: function(data, _parent, _target, _callbacks, data_defaults) {
var self = this,
parent = _parent || $('#device-content'),
target = _target || $('#device-view', parent),
_callbacks = _callbacks || {},
callbacks = {
save_success: _callbacks.save_success,
save_error: _callbacks.save_error || function(_data, status, type) {
if (status === 200 && type === 'mac_address') {
monster.ui.alert(self.i18n.active().callflows.device.this_mac_address_is_already_in_use);
}
},
delete_success: _callbacks.delete_success,
delete_error: _callbacks.delete_error,
after_render: _callbacks.after_render
},
defaults = {
data: $.extend(true, {
enabled: true,
caller_id: {
external: {},
internal: {},
emergency: {}
},
ringtones: {},
ignore_completed_elsewhere: true,
call_restriction: { closed_groups: 'inherit' },
media: {
secure_rtp: 'none',
audio: {
codecs: ['PCMU', 'PCMA']
},
video: {
codecs: []
},
fax: {
option: 'false'
},
fax_option: false
},
sip: {
method: 'password',
invite_format: 'contact',
username: 'user_' + monster.util.randomString(6),
password: monster.util.randomString(12),
expire_seconds: '360'
},
contact_list: {
exclude: false
},
call_forward: {},
music_on_hold: {}
}, data_defaults || {}),
field_data: {
users: [],
call_restriction: {},
sip: {
methods: {
'password': self.i18n.active().callflows.device.password,
'ip': 'IP'
},
invite_formats: {
'username': 'Username',
'npan': 'NPA NXX XXXX',
'e164': 'E. 164',
'1npan': '1npan',
'route': 'Route',
'contact': 'Contact'
}
},
media: {
secure_rtp: {
value: 'none',
options: {
'none': self.i18n.active().callflows.device.none,
'srtp': self.i18n.active().callflows.device.srtp,
'zrtp': self.i18n.active().callflows.device.zrtp
}
},
fax: {
options: {
'auto': self.i18n.active().callflows.device.auto_detect,
'true': self.i18n.active().callflows.device.always_force,
'false': self.i18n.active().callflows.device.disabled
}
},
audio: {
codecs: {
'OPUS': 'OPUS',
'CELT@32000h': 'Siren @ 32Khz',
'G7221@32000h': 'G722.1 @ 32khz',
'G7221@16000h': 'G722.1 @ 16khz',
'G722': 'G722',
'speex@32000h': 'Speex @ 32khz',
'speex@16000h': 'Speex @ 16khz',
'PCMU': 'G711u / PCMU - 64kbps (North America)',
'PCMA': 'G711a / PCMA - 64kbps (Elsewhere)',
'G729': 'G729 - 8kbps (Requires License)',
'GSM': 'GSM',
'CELT@48000h': 'Siren (HD) @ 48kHz',
'CELT@64000h': 'Siren (HD) @ 64kHz'
}
},
video: {
codecs: {
'VP8': 'VP8',
'H264': 'H264',
'H263': 'H263',
'H261': 'H261'
}
}
},
hide_owner: data.hide_owner || false,
outbound_flags: data.outbound_flags ? data.outbound_flags.join(', ') : data.outbound_flags
},
functions: {
inArray: function(value, array) {
if (array) {
return ($.inArray(value, array) === -1) ? false : true;
} else {
return false;
}
}
}
},
parallelRequests = function(deviceData) {
monster.parallel({
list_classifier: function(callback) {
self.callApi({
resource: 'numbers.listClassifiers',
data: {
accountId: self.accountId,
filters: {
paginate: false
}
},
success: function(_data_classifiers) {
if ('data' in _data_classifiers) {
$.each(_data_classifiers.data, function(k, v) {
defaults.field_data.call_restriction[k] = {
friendly_name: v.friendly_name
};
defaults.data.call_restriction[k] = { action: 'inherit' };
});
}
callback(null, _data_classifiers);
}
});
},
account: function(callback) {
self.callApi({
resource: 'account.get',
data: {
accountId: self.accountId
},
success: function(_data, status) {
$.extend(defaults.field_data.sip, {
realm: _data.data.realm
});
callback(null, _data);
}
});
},
user_list: function(callback) {
self.callApi({
resource: 'user.list',
data: {
accountId: self.accountId,
filters: {
paginate: false
}
},
success: function(_data, status) {
_data.data.sort(function(a, b) {
return (a.first_name + a.last_name).toLowerCase() < (b.first_name + b.last_name).toLowerCase() ? -1 : 1;
});
_data.data.unshift({
id: '',
first_name: '- No',
last_name: 'owner -'
});
if (deviceData.hasOwnProperty('device_type') && deviceData.device_type === 'mobile') {
var userData = _.find(_data.data, function(user) { return user.id === deviceData.owner_id; });
if (userData) {
defaults.field_data.users = userData;
} else {
defaults.field_data.users = {
first_name: '- No',
last_name: 'owner -'
};
}
} else {
defaults.field_data.users = _data.data;
}
callback(null, _data);
}
});
},
media_list: function(callback) {
self.callApi({
resource: 'media.list',
data: {
accountId: self.accountId,
filters: {
paginate: false
}
},
success: function(_data, status) {
_data.data.unshift(
{
id: '',
name: self.i18n.active().callflows.device.default_music
},
{
id: 'silence_stream://300000',
name: self.i18n.active().callflows.device.silence
},
{
id: 'shoutcast',
name: self.i18n.active().callflows.accountSettings.musicOnHold.shoutcastURL
}
);
defaults.field_data.music_on_hold = _data.data;
callback(null, _data);
}
});
},
provisionerData: function(callback) {
if (monster.config.api.hasOwnProperty('provisioner') && monster.config.api.provisioner) {
self.deviceGetDataProvisoner(function(data) {
callback(null, data);
});
} else {
callback(null, {});
}
}
},
function(err, results) {
var render_data = self.devicePrepareDataForTemplate(data, defaults, $.extend(true, results, {
get_device: deviceData
}));
self.deviceRender(render_data, target, callbacks);
if (typeof callbacks.after_render === 'function') {
callbacks.after_render();
}
});
};
if (typeof data === 'object' && data.id) {
self.deviceGet(data.id, function(_data, status) {
defaults.data.device_type = 'sip_device';
if ('media' in _data && 'encryption' in _data.media) {
defaults.field_data.media.secure_rtp.value = _data.media.encryption.enforce_security ? _data.media.encryption.methods[0] : 'none';
}
if ('sip' in _data && 'realm' in _data.sip) {
defaults.field_data.sip.realm = _data.sip.realm;
}
self.deviceMigrateData(_data);
parallelRequests(_data);
});
} else {
parallelRequests(defaults);
}
},
devicePrepareDataForTemplate: function(data, dataGlobal, results) {
var self = this,
dataDevice = results.get_device,
dataProvisioner = results.provisionerData;
if (typeof data === 'object' && data.id) {
dataGlobal = $.extend(true, dataGlobal, { data: dataDevice });
}
if (dataDevice.hasOwnProperty('media') && dataDevice.media.hasOwnProperty('audio')) {
// If the codecs property is defined, override the defaults with it. Indeed, when an empty array is set as the
// list of codecs, it gets overwritten by the extend function otherwise.
if (dataDevice.media.audio.hasOwnProperty('codecs')) {
dataGlobal.data.media.audio.codecs = dataDevice.media.audio.codecs;
}
if (dataDevice.media.video.hasOwnProperty('codecs')) {
dataGlobal.data.media.video.codecs = dataDevice.media.video.codecs;
}
}
_.each(dataGlobal.field_data.call_restriction, function(restriction, key) {
restriction.value = dataGlobal.data.call_restriction[key].action;
});
dataGlobal.field_data.provisioner = dataProvisioner;
dataGlobal.field_data.provisioner.isEnabled = !_.isEmpty(dataProvisioner);
if (dataGlobal.field_data.provisioner.isEnabled) {
var default_provision_data = {
voicemail_beep: 1, //ie enabled
time_format: '12',
hotline: '',
vlan: {
enable: false,
number: ''
},
date_format: 'middle-endian'
};
dataGlobal.data.provision = $.extend(true, {}, default_provision_data, dataGlobal.data.provision);
}
dataGlobal.extra = dataGlobal.extra || {};
dataGlobal.extra.isShoutcast = false;
// if the value is set to a stream, we need to set the value of the media_id to shoutcast so it gets selected by the old select mechanism,
// but we also need to store the value so we can display it
if (dataGlobal.data.hasOwnProperty('music_on_hold') && dataGlobal.data.music_on_hold.hasOwnProperty('media_id')) {
if (dataGlobal.data.music_on_hold.media_id.indexOf('://') >= 0) {
if (dataGlobal.data.music_on_hold.media_id !== 'silence_stream://300000') {
dataGlobal.extra.isShoutcast = true;
dataGlobal.extra.shoutcastValue = dataGlobal.data.music_on_hold.media_id;
dataGlobal.data.music_on_hold.media_id = 'shoutcast';
}
}
}
return dataGlobal;
},
deviceGetValidationByDeviceType: function(deviceType) {
var self = this,
i18n = self.i18n.active(),
validation = {
ata: {
'sip.ip': {
required: true,
ipv4: true
}
},
sip_uri: {},
sip_device: {
'mac_address': { mac: true },
'sip_expire_seconds': { digits: true },
'sip.ip': {
ipv4: true,
required: true
},
'extra.shoutcastUrl': { protocol: true }
},
fax: {
'mac_address': { mac: true },
'sip_expire_seconds': { digits: true },
'sip.ip': {
ipv4: true,
required: true
}
},
cellphone: {},
smartphone: {
'sip_expire_seconds': { digits: true },
'sip.ip': {
ipv4: true,
required: true
}
},
landline: {},
softphone: {
'sip_expire_seconds': { digits: true },
'extra.shoutcastUrl': { protocol: true }
},
mobile: {
'mdn': { digits: true },
'sip_expire_seconds': { digits: true },
'extra.shoutcastUrl': { protocol: true }
}
},
deviceTypeValidation = {
rules: validation[deviceType]
};
if (_.includes(['ata', 'fax', 'mobile', 'sip_device', 'softphone'], deviceType)) {
_.merge(deviceTypeValidation, {
rules: {
'caller_id.asserted.name': { regex: /^[0-9A-Za-z ,]{0,30}$/ },
'caller_id.asserted.number': { phoneNumber: true },
'caller_id.asserted.realm': { realm: true }
},
messages: {
'caller_id.asserted.name': { regex: i18n.callflows.device.validation.caller_id.name },
'caller_id.asserted.number': { regex: i18n.callflows.device.validation.caller_id.number },
'caller_id.asserted.realm': { regex: i18n.callflows.device.validation.caller_id.realm }
}
});
}
return deviceTypeValidation;
},
deviceRender: function(data, target, callbacks) {
var self = this,
device_html;
if ('media' in data.data && 'fax_option' in data.data.media) {
data.data.media.fax_option = (data.data.media.fax_option === 'auto' || data.data.media.fax_option === true);
}
if (typeof data.data === 'object' && data.data.device_type) {
device_html = $(self.getTemplate({
name: 'device-' + data.data.device_type,
data: _.merge({
showPAssertedIdentity: monster.config.whitelabel.showPAssertedIdentity
}, data),
submodule: 'device'
}));
var deviceForm = device_html.find('#device-form');
if (monster.config.api.hasOwnProperty('provisioner') && monster.config.api.provisioner) {
self.deviceSetProvisionerStuff(device_html, data);
}
/* Do device type specific things here */
if ($.inArray(data.data.device_type, ['fax', 'softphone', 'sip_device', 'smartphone', 'mobile', 'ata']) > -1) {
monster.ui.protectField(device_html.find('#sip_password'), device_html);
}
monster.ui.validate(deviceForm, self.deviceGetValidationByDeviceType(data.data.device_type));
if (!$('#owner_id', device_html).val()) {
$('#edit_link', device_html).hide();
}
device_html.find('input[data-mask]').each(function() {
var $this = $(this);
monster.ui.mask($this, $this.data('mask'));
});
if (!$('#music_on_hold_media_id', device_html).val()) {
$('#edit_link_media', device_html).hide();
}
if (data.data.sip && data.data.sip.method === 'ip') {
$('#username_block', device_html).hide();
} else {
$('#ip_block', device_html).hide();
}
} else {
device_html = $(self.getTemplate({
name: 'general_edit',
submodule: 'device'
}));
$('.media_pane', device_html).hide();
}
$('*[rel=popover]:not([type="text"])', device_html).popover({
trigger: 'hover'
});
$('*[rel=popover][type="text"]', device_html).popover({
trigger: 'focus'
});
self.winkstartTabs(device_html);
self.deviceBindEvents({
data: data,
template: device_html,
callbacks: callbacks
});
(target)
.empty()
.append(device_html);
$('.media_tabs .buttons[device_type="sip_device"]', device_html).trigger('click');
},
/**
* Bind events for the device edit template
* @param {Object} args
* @param {Object} args.data
* @param {Object} args.template
* @param {Object} args.callbacks
* @param {Function} args.callbacks.save_success
* @param {Function} args.callbacks.delete_success
*/
deviceBindEvents: function(args) {
var self = this,
data = args.data,
callbacks = args.callbacks,
device_html = args.template;
if (typeof data.data === 'object' && data.data.device_type) {
var deviceForm = device_html.find('#device-form');
$('#owner_id', device_html).change(function() {
!$('#owner_id option:selected', device_html).val() ? $('#edit_link', device_html).hide() : $('#edit_link', device_html).show();
});
$('.inline_action', device_html).click(function(ev) {
var _data = ($(this).data('action') === 'edit') ? { id: $('#owner_id', device_html).val() } : {},
_id = _data.id;
ev.preventDefault();
monster.pub('callflows.user.popupEdit', {
data: _data,
callback: function(user) {
/* Create */
if (!_id) {
$('#owner_id', device_html).append('<option id="' + user.id + '" value="' + user.id + '">' + user.first_name + ' ' + user.last_name + '</option>');
$('#owner_id', device_html).val(user.id);
$('#edit_link', device_html).show();
} else {
/* Update */
if (_data.hasOwnProperty('id')) {
$('#owner_id #' + user.id, device_html).text(user.first_name + ' ' + user.last_name);
/* Delete */
} else {
$('#owner_id #' + _id, device_html).remove();
$('#edit_link', device_html).hide();
}
}
}
});
});
$('.device-save', device_html).click(function(ev) {
ev.preventDefault();
var $this = $(this);
if (!$this.hasClass('disabled')) {
$this.addClass('disabled');
if (monster.ui.valid(deviceForm)) {
var form_data = monster.ui.getFormData('device-form');
if (form_data.hasOwnProperty('music_on_hold') && form_data.music_on_hold.media_id === 'shoutcast') {
form_data.music_on_hold.media_id = device_html.find('.shoutcast-url-input').val();
}
self.deviceCleanFormData(form_data);
if (form_data.hasOwnProperty('provision') && form_data.provision.hasOwnProperty('endpoint_brand') && form_data.provision.endpoint_brand !== 'none') {
var modelArray = $('.dropdown_family[data-brand="' + form_data.provision.endpoint_brand + '"]', device_html).val().split('.'),
endpoint_family = modelArray[0],
endpoint_model = modelArray[1];
// We have to set this manually since we have 3 dropdown with the same name we don't know which selected one is the correct one..
form_data.provision.endpoint_model = endpoint_model;
form_data.provision.endpoint_family = endpoint_family;
}
self.deviceSave(form_data, data, callbacks.save_success);
} else {
$this.removeClass('disabled');
monster.ui.alert('error', self.i18n.active().callflows.device.there_were_errors_on_the_form);
}
}
});
if (data.device_type !== 'mobile') {
$('.device-delete', device_html).click(function(ev) {
ev.preventDefault();
monster.ui.confirm(self.i18n.active().callflows.device.are_you_sure_you_want_to_delete, function() {
self.deviceDelete(data.data.id, callbacks.delete_success);
});
});
}
device_html.find('#sip_method').on('change', function() {
if ($('#sip_method option:selected', device_html).val() === 'ip') {
$('#ip_block', device_html).slideDown();
$('#username_block', device_html).slideUp();
} else {
$('#username_block', device_html).slideDown();
$('#ip_block', device_html).slideUp();
}
});
$('#music_on_hold_media_id', device_html).change(function() {
!$('#music_on_hold_media_id option:selected', device_html).val() ? $('#edit_link_media', device_html).hide() : $('#edit_link_media', device_html).show();
device_html.find('.shoutcast-div').toggleClass('active', $(this).val() === 'shoutcast');
});
$('.inline_action_media', device_html).click(function(ev) {
var _data = ($(this).data('action') === 'edit') ? { id: $('#music_on_hold_media_id', device_html).val() } : {},
_id = _data.id;
ev.preventDefault();
monster.pub('callflows.media.editPopup', {
data: _data,
callback: function(media) {
/* Create */
if (!_id) {
$('#music_on_hold_media_id', device_html).append('<option id="' + media.id + '" value="' + media.id + '">' + media.name + '</option>');
$('#music_on_hold_media_id', device_html).val(media.id);
$('#edit_link_media', device_html).show();
} else {
/* Update */
if (media.hasOwnProperty('id')) {
$('#music_on_hold_media_id #' + media.id, device_html).text(media.name);
/* Delete */
} else {
$('#music_on_hold_media_id #' + _id, device_html).remove();
$('#edit_link_media', device_html).hide();
}
}
}
});
});
} else {
$('.media_tabs .buttons', device_html).click(function() {
var $this = $(this);
$('.media_pane', device_html).show();
if (!$this.hasClass('current')) {
$('.media_tabs .buttons').removeClass('current');
$this.addClass('current');
data.data.device_type = $this.attr('device_type');
self.deviceFormatData(data);
self.deviceRender(data, $('.media_pane', device_html), callbacks);
}
});
}
},
deviceSetProvisionerStuff: function(device_html, data) {
var self = this,
set_value = function(brand_name, model_family, model_name) {
device_html.find('.dropdown_family').hide();
if (brand_name in data.field_data.provisioner.brands) {
device_html.find('#dropdown_brand').val(brand_name);
device_html
.find('.dropdown_family[data-brand="' + brand_name + '"]')
.show()
.val(model_family + '.' + model_name);
}
},
provisionData = data.data.provision,
regex_brands = {
'00085d': 'aastra',
'0010bc': 'aastra',
'00036b': 'cisco',
'00000c': 'cisco',
'000142': 'cisco',
'000143': 'cisco',
'000163': 'cisco',
'000164': 'cisco',
'000196': 'cisco',
'000197': 'cisco',
'0001c7': 'cisco',
'0001c9': 'cisco',
'000f23': 'cisco',
'0013c4': 'cisco',
'0016c8': 'cisco',
'001818': 'cisco',
'00175a': 'cisco',
'001795': 'cisco',
'001A2f': 'cisco',
'001c58': 'cisco',
'001dA2': 'cisco',
'002155': 'cisco',
'000e84': 'cisco',
'000e38': 'cisco',
'00070e': 'cisco',
'001bd4': 'cisco',
'001930': 'cisco',
'0019aa': 'cisco',
'001d45': 'cisco',
'001ef7': 'cisco',
'000e08': 'cisco',
'1cdf0f': 'cisco',
'e05fb9': 'cisco',
'5475d0': 'cisco',
'c46413': 'cisco',
'000Ffd3': 'digium',
'000b82': 'grandstream',
'08000f': 'mitel',
'1045bE': 'norphonic',
'0050c2': 'norphonic',
'0004f2': 'polycom',
'00907a': 'polycom',
'000413': 'snom',
'001f9f': 'thomson',
'00147f': 'thomson',
'642400': 'xorcom',
'001565': 'yealink'
};
set_value(provisionData.endpoint_brand, provisionData.endpoint_family, provisionData.endpoint_model);
device_html.find('#dropdown_brand').on('change', function() {
set_value($(this).val());
});
device_html.find('#mac_address').on('keyup', function() {
var mac_address = $(this).val().replace(/[^0-9a-fA-F]/g, '');
if (mac_address in regex_brands) {
set_value(regex_brands[mac_address]);
}
});
},
deviceFormatData: function(data) {
if (data.data.device_type === 'smartphone' || data.data.device_type === 'landline' || data.data.device_type === 'cellphone') {
data.data.call_forward = {
enabled: true,
require_keypress: true,
keep_caller_id: true
};
} else {
data.data.call_forward = {
enabled: false
};
}
if (data.data.device_type === 'sip_uri') {
data.data.sip.invite_format = 'route';
}
if (data.data.device_type === 'mobile') {
if (!('mobile' in data.data)) {
data.data.mobile = {
mdn: ''
};
}
}
if (data.data.device_type === 'fax') {
data.data.media.fax_option = true;
data.data.media.fax.option = 'true';
} else {
data.data.media.fax_option = false;
data.data.media.fax.option = 'false';
}
},
deviceMigrateData: function(data) {
var self = this;
if (data.hasOwnProperty('media') && data.media.hasOwnProperty('audio') && data.media.audio.hasOwnProperty('codecs')) {
var mapMigrateCodec = {
'Speex': 'speex@16000h',
'G722_16': 'G7221@16000h',
'G722_32': 'G7221@32000h',
'CELT_48': 'CELT@48000h',
'CELT_64': 'CELT@64000h'
},
newCodecList = [];
_.each(data.media.audio.codecs, function(codec) {
mapMigrateCodec.hasOwnProperty(codec) ? newCodecList.push(mapMigrateCodec[codec]) : newCodecList.push(codec);
});
data.media.audio.codecs = newCodecList;
}
if (data.device_type === 'cell_phone') {
data.device_type = 'cellphone';
}
if (typeof data.media === 'object' && typeof data.media.fax === 'object' && 'codecs' in data.media.fax) {
delete data.media.fax.codecs;
}
if ('status' in data) {
data.enabled = data.status;
delete data.status;
}
if (data.hasOwnProperty('ignore_complete_elsewhere')) {
data.ignore_completed_elsewhere = data.ignore_complete_elsewhere;
delete data.ignore_complete_elsewhere;
}
return data;
},
deviceNormalizeData: function(data) {
var self = this;
if (data.hasOwnProperty('provision')) {
if (data.provision.endpoint_brand === 'none') {
delete data.provision;
} else {
if (data.provision.voicemail_beep !== 0) {
delete data.provision.voicemail_beep;
}
}
}
if (data.hasOwnProperty('media') && data.media.hasOwnProperty('fax_option') && data.media.fax_option === 'auto') {
delete data.media.fax_option;
}
if ('media' in data && 'fax' in data.media && 'fax_option' in data.media) {
data.media.fax.option = data.media.fax_option.toString();
}
if ('media' in data && 'secure_rtp' in data.media) {
delete data.media.secure_rtp;
}
if ('media' in data && 'bypass_media' in data.media) {
delete data.media.bypass_media;
}
self.compactObject(data.caller_id);
if (_.isEmpty(data.caller_id)) {
delete data.caller_id;
}
if (!data.music_on_hold.media_id) {
delete data.music_on_hold.media_id;
}
if (!data.owner_id) {
delete data.owner_id;
}
if ($.isEmptyObject(data.call_forward)) {
delete data.call_forward;
}
if (!data.mac_address) {
delete data.mac_address;
}
if (data.sip.method !== 'ip') {
delete data.sip.ip;
}
if (typeof data.outbound_flags === 'string') {
data.outbound_flags = data.outbound_flags.split(/,/);
/* Get rid of empty string */
var new_flags = [];
$.each(data.outbound_flags, function(k, v) {
if (v.replace(/\s/g, '') !== '') {
new_flags.push(v);
}
});
data.outbound_flags = new_flags;
}
if (data.device_type === 'fax') {
if (!('outbound_flags' in data)) {
data.outbound_flags = ['fax'];
} else if (data.outbound_flags.indexOf('fax') < 0) {
data.outbound_flags.splice(0, 0, 'fax');
}
}
if (data.ringtones && 'internal' in data.ringtones && data.ringtones.internal === '') {
delete data.ringtones.internal;
}
if (data.ringtones && 'external' in data.ringtones && data.ringtones.external === '') {
delete data.ringtones.external;
}
// For devices who don't have sip creds, we need to use username, for sip url we already set it to "route", and for the others, the default is applied: "contact"
if ($.inArray(data.device_type, ['landline', 'cellphone']) >= 0) {
data.sip.invite_format = 'username';
}
if ($.inArray(data.device_type, ['fax', 'mobile', 'softphone', 'sip_device', 'smartphone']) < 0) {
delete data.call_restriction;
}
if (data.hasOwnProperty('presence_id') && data.presence_id === '') {
delete data.presence_id;
}
return data;
},
deviceCleanFormData: function(form_data) {
if ('provision' in form_data && form_data.provision.voicemail_beep === true) {
form_data.provision.voicemail_beep = 0;
}
if (form_data.mac_address) {
form_data.mac_address = form_data.mac_address.toLowerCase();
if (form_data.mac_address.match(/^(((\d|([a-f]|[A-F])) {2}-) {5}(\d|([a-f]|[A-F])) {2})$/)) {
form_data.mac_address = form_data.mac_address.replace(/-/g, ':');
} else if (form_data.mac_address.match(/^(((\d|([a-f]|[A-F])) {2}) {5}(\d|([a-f]|[A-F])) {2})$/)) {
form_data.mac_address = form_data.mac_address.replace(/(.{2})/g, '$1:').slice(0, -1);
}
}
if (form_data.caller_id) {
form_data.caller_id.internal.number = form_data.caller_id.internal.number.replace(/\s|\(|\)|-|\./g, '');
form_data.caller_id.external.number = form_data.caller_id.external.number.replace(/\s|\(|\)|-|\./g, '');
form_data.caller_id.emergency.number = form_data.caller_id.emergency.number.replace(/\s|\(|\)|-|\./g, '');
var assertedNumber = _.get(form_data.caller_id, 'asserted.number', '');
if(!_.isEmpty(assertedNumber)) {
assertedNumber = monster.util.getFormatPhoneNumber(assertedNumber).e164Number;
}
// Need to keep the empty string so the new value is not lost when merging the form data with the original data
_.set(form_data.caller_id, 'asserted.number', assertedNumber);
}
if ('media' in form_data && 'audio' in form_data.media) {
form_data.media.audio.codecs = $.map(form_data.media.audio.codecs, function(val) { return (val) ? val : null; });
}
if ('media' in form_data && 'video' in form_data.media) {
form_data.media.video.codecs = $.map(form_data.media.video.codecs, function(val) { return (val) ? val : null; });
}
if (form_data.device_type === 'smartphone' || form_data.device_type === 'landline' || form_data.device_type === 'cellphone') {
form_data.call_forward.number = form_data.call_forward.number.replace(/\s|\(|\)|-|\./g, '');
form_data.enabled = form_data.call_forward.enabled;
}
if ('extra' in form_data && form_data.extra.notify_unregister === true) {
form_data.suppress_unregister_notifications = false;
} else {
form_data.suppress_unregister_notifications = true;
}
if ('extra' in form_data && 'closed_groups' in form_data.extra) {
form_data.call_restriction.closed_groups = { action: form_data.extra.closed_groups ? 'deny' : 'inherit' };
}
if ($.inArray(form_data.device_type, ['sip_device', 'mobile', 'softphone']) > -1) {
if ('extra' in form_data) {
form_data.media.encryption = form_data.media.encryption || {};
if ($.inArray(form_data.extra.encryptionMethod, ['srtp', 'zrtp']) > -1) {
form_data.media.encryption.enforce_security = true;
form_data.media.encryption.methods = [form_data.extra.encryptionMethod];
} else {
form_data.media.encryption.methods = [];
form_data.media.encryption.enforce_security = false;
}
}
}
delete form_data.extra;
return form_data;
},
deviceFixArrays: function(data, data2) {
if (typeof data.media === 'object' && typeof data2.media === 'object') {
(data.media.audio || {}).codecs = (data2.media.audio || {}).codecs;
(data.media.video || {}).codecs = (data2.media.video || {}).codecs;
}
if ('media' in data2 && 'encryption' in data2.media && 'methods' in data2.media.encryption) {
data.media.encryption = data.media.encryption || {};
data.media.encryption.methods = data2.media.encryption.methods;
}
return data;
},
deviceSave: function(form_data, data, success) {
var self = this,
id = (typeof data.data === 'object' && data.data.id) ? data.data.id : undefined,
normalized_data = self.deviceFixArrays(self.deviceNormalizeData($.extend(true, {}, data.data, form_data)), form_data);
if (id) {
self.deviceUpdate(normalized_data, function(_data, status) {
success && success(_data, status, 'update');
});
} else {
self.deviceCreate(normalized_data, function(_data, status) {
success && success(_data, status, 'create');
});
}
},
deviceList: function(callback) {
var self = this;
self.callApi({
resource: 'device.list',
data: {
accountId: self.accountId,
filters: {
paginate: false
}
},
success: function(data) {
callback && callback(data.data);
}
});
},
deviceGet: function(deviceId, callback) {
var self = this;
self.callApi({
resource: 'device.get',
data: {
accountId: self.accountId,
deviceId: deviceId
},
success: function(data) {
callback && callback(data.data);
}
});
},
deviceCreate: function(data, callback) {
var self = this;
self.callApi({
resource: 'device.create',
data: {
accountId: self.accountId,
data: data
},
success: function(data) {
callback && callback(data.data);
}
});
},
deviceUpdate: function(data, callback) {
var self = this;
self.callApi({
resource: 'device.update',
data: {
accountId: self.accountId,
deviceId: data.id,
data: data
},
success: function(data) {
callback && callback(data.data);
}
});
},
deviceDelete: function(deviceId, callback) {
var self = this;
self.callApi({
resource: 'device.delete',
data: {
accountId: self.accountId,
deviceId: deviceId
},
success: function(data) {
callback && callback(data.data);
}
});
},
deviceGetDataProvisoner: function(callback) {
var self = this;
monster.request({
resource: 'callflows.device.getProvisionerPhones',
data: {
},
success: function(data) {
data = self.deviceFormatDataProvisioner(data.data);
callback && callback(data);
}
});
},
deviceFormatDataProvisioner: function(data) {
var self = this,
formattedData = {
brands: data
};
return formattedData;
},
deviceDefineActions: function(args) {
var self = this,
callflow_nodes = args.actions;
$.extend(callflow_nodes, {
'device[id=*]': {
name: self.i18n.active().callflows.device.device,
icon: 'phone',
category: self.i18n.active().oldCallflows.advanced_cat,
module: 'device',
tip: self.i18n.active().callflows.device.device_tip,
data: {
id: 'null'
},
rules: [
{
type: 'quantity',
maxSize: '1'
}
],
isUsable: 'true',
weight: 10,
caption: function(node, caption_map) {
var id = node.getMetadata('id'),
returned_value = '';
if (id in caption_map) {
returned_value = caption_map[id].name;
}
return returned_value;
},
edit: function(node, callback) {
var _this = this;
self.deviceList(function(devices) {
var popup, popup_html;
popup_html = $(self.getTemplate({
name: 'callflowEdit',
data: {
can_call_self: node.getMetadata('can_call_self') || false,
parameter: {
name: 'timeout (s)',
value: node.getMetadata('timeout') || '20'
},
objects: {
items: _.sortBy(devices, 'name'),
selected: node.getMetadata('id') || ''
}
},
submodule: 'device'
}));
if ($('#device_selector option:selected', popup_html).val() === undefined) {
$('#edit_link', popup_html).hide();
}
$('.inline_action', popup_html).click(function(ev) {
var _data = ($(this).data('action') === 'edit') ? { id: $('#device_selector', popup_html).val() } : {};
ev.preventDefault();
self.devicePopupEdit({
data: _data,
callback: function(device) {
node.setMetadata('id', device.id || 'null');
node.setMetadata('timeout', $('#parameter_input', popup_html).val());
node.setMetadata('can_call_self', $('#device_can_call_self', popup_html).is(':checked'));
node.caption = device.name || '';
popup.dialog('close');
}
});
});
$('#add', popup_html).click(function() {
node.setMetadata('id', $('#device_selector', popup_html).val());
node.setMetadata('timeout', $('#parameter_input', popup_html).val());
node.setMetadata('can_call_self', $('#device_can_call_self', popup_html).is(':checked'));
node.caption = $('#device_selector option:selected', popup_html).text();
popup.dialog('close');
});
popup = monster.ui.dialog(popup_html, {
title: self.i18n.active().callflows.device.device_title,
beforeClose: function() {
if (typeof callback === 'function') {
callback();
}
}
});
});
},
listEntities: function(callback) {
monster.parallel({
device: function(callback) {
self.callApi({
resource: 'device.list',
data: {
accountId: self.accountId,
filters: {
paginate: false
}
},
success: function(data, status) {
callback && callback(null, data.data);
}
});
},
status: function(callback) {
self.callApi({
resource: 'device.getStatus',
data: {
accountId: self.accountId,
filters: {
paginate: false
}
},
success: function(data, status) {
callback && callback(null, data.data);
}
});
}
},
function(err, results) {
var registeredDevices = _.map(results.status, function(registration) { if (registration.registered === true) { return registration.device_id; } }),
deviceIcons = {
'cellphone': 'fa fa-phone',
'smartphone': 'icon-telicon-mobile-phone',
'landline': 'icon-telicon-home',
'mobile': 'icon-telicon-sprint-phone',
'softphone': 'icon-telicon-soft-phone',
'sip_device': 'icon-telicon-voip-phone',
'sip_uri': 'icon-telicon-voip-phone',
'fax': 'icon-telicon-fax',
'ata': 'icon-telicon-ata',
'unknown': 'fa fa-circle'
};
_.each(results.device, function(device) {
var dataTemplate = device;
dataTemplate.extra = {
deviceIcon: deviceIcons.hasOwnProperty(device.device_type) ? deviceIcons[device.device_type] : deviceIcons.unknown,
isRegistered: device.enabled ? (['sip_device', 'smartphone', 'softphone', 'fax', 'ata'].indexOf(device.device_type) >= 0 ? registeredDevices.indexOf(device.id) >= 0 : true) : false
};
// no jQuery wrapper since this template will be inserted directly with Handlebars
device.customEntityTemplate = self.getTemplate({
name: 'entity-element',
data: dataTemplate,
submodule: 'device'
});
});
callback && callback(results.device);
});
},
editEntity: 'callflows.device.edit'
}
});
}
};
return app;
});