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.
 
 
 

3872 lines
106 KiB

define(function(require){
var $ = require('jquery'),
_ = require('underscore'),
chosen = require('chosen'),
monster = require('monster'),
timezone = require('monster-timezone'),
toastr = require('toastr');
var app = {
requests: {
/* Users */
'voip.users.getUsers': {
url: 'accounts/{accountId}/users',
verb: 'GET'
},
'voip.users.updateUser': {
url: 'accounts/{accountId}/users/{userId}',
verb: 'POST'
},
'voip.users.createUser': {
url: 'accounts/{accountId}/users',
verb: 'PUT'
},
'voip.users.getUser': {
url: 'accounts/{accountId}/users/{userId}',
verb: 'GET'
},
'voip.users.deleteUser': {
url: 'accounts/{accountId}/users/{userId}',
verb: 'DELETE'
},
/* VMBoxes*/
'voip.users.listVMBoxes': {
url: 'accounts/{accountId}/vmboxes',
verb: 'GET'
},
'voip.users.createVMBox': {
url: 'accounts/{accountId}/vmboxes',
verb: 'PUT'
},
'voip.users.getVMBox': {
url: 'accounts/{accountId}/vmboxes/{vmboxId}',
verb: 'GET'
},
'voip.users.updateVMBox': {
url: 'accounts/{accountId}/vmboxes/{vmboxId}',
verb: 'POST'
},
'voip.users.deleteVMBox': {
url: 'accounts/{accountId}/vmboxes/{vmboxId}',
verb: 'DELETE'
},
'voip.users.listUserVMBoxes': {
url: 'accounts/{accountId}/vmboxes?filter_owner_id={userId}',
verb: 'GET'
},
/* Callflows */
'voip.users.getCallflows': {
url: 'accounts/{accountId}/callflows',
verb: 'GET'
},
'voip.users.createCallflow': {
url: 'accounts/{accountId}/callflows',
verb: 'PUT'
},
'voip.users.listUserCallflows': {
url: 'accounts/{accountId}/callflows?filter_owner_id={userId}',
verb: 'GET'
},
'voip.users.getCallflow': {
url: 'accounts/{accountId}/callflows/{callflowId}',
verb: 'GET'
},
'voip.users.updateCallflow': {
url: 'accounts/{accountId}/callflows/{callflowId}',
verb: 'POST'
},
'voip.users.deleteCallflow': {
url: 'accounts/{accountId}/callflows/{callflowId}',
verb: 'DELETE'
},
'voip.users.listConfNumbers': {
url: 'accounts/{accountId}/callflows?filter_type=conference',
verb: 'GET'
},
/* Devices */
'voip.users.listDevices': {
url: 'accounts/{accountId}/devices',
verb: 'GET'
},
'voip.users.listUserDevices': {
url: 'accounts/{accountId}/devices?filter_owner_id={userId}',
verb: 'GET'
},
'voip.users.getDevice': {
url: 'accounts/{accountId}/devices/{deviceId}',
verb: 'GET'
},
'voip.users.updateDevice': {
url: 'accounts/{accountId}/devices/{deviceId}',
verb: 'POST'
},
'voip.users.deleteDevice': {
url: 'accounts/{accountId}/devices/{deviceId}',
verb: 'DELETE'
},
/* Directories */
'voip.users.listDirectories': {
url: 'accounts/{accountId}/directories',
verb: 'GET'
},
'voip.users.createDirectory': {
url: 'accounts/{accountId}/directories',
verb: 'PUT'
},
/* Conferences */
'voip.users.createConference': {
url: 'accounts/{accountId}/conferences',
verb: 'PUT'
},
'voip.users.getConference': {
url: 'accounts/{accountId}/conferences/{conferenceId}',
verb: 'GET'
},
'voip.users.updateConference': {
url: 'accounts/{accountId}/conferences/{conferenceId}',
verb: 'POST'
},
'voip.users.deleteConference': {
url: 'accounts/{accountId}/conferences/{conferenceId}',
verb: 'DELETE'
},
'voip.users.listUserConferences': {
url: 'accounts/{accountId}/conferences?filter_owner_id={userId}',
verb: 'GET'
},
/* Media */
'voip.users.listMedia': {
url: 'accounts/{accountId}/media?key_missing=type',
verb: 'GET'
},
'voip.users.createMedia': {
url: 'accounts/{accountId}/media',
verb: 'PUT'
},
'voip.users.deleteMedia': {
url: 'accounts/{accountId}/media/{mediaId}',
verb: 'DELETE'
},
'voip.users.uploadMedia': {
url: 'accounts/{accountId}/media/{mediaId}/raw',
verb: 'POST',
type: 'application/x-base64'
},
/* Misc */
'voip.users.getNumbers': {
url: 'accounts/{accountId}/phone_numbers',
verb: 'GET'
},
'voip.users.resendInstructions': {
apiRoot: 'apps/voip/submodules/users/fixtures/',
url: 'resendInstructions.json',
verb: 'POST'
},
'voip.users.resetPassword': {
apiRoot: 'apps/voip/submodules/users/fixtures/',
url: 'resetPassword.json',
verb: 'POST'
}
/*,
'voip.users.resendInstructions': {
url: 'accounts/{accountId}/users/{userId}/resend_instructions',
verb: 'POST'
},
'voip.users.resetPassword': {
url: 'accounts/{accountId}/users/{userId}/reset_password',
verb: 'POST'
},
*/
},
subscribe: {
'voip.users.render': 'usersRender'
},
/* Users */
/* args: parent and userId */
usersRender: function(args) {
var self = this,
args = args || {},
parent = args.parent || $('.right-content'),
_userId = args.userId,
_openedTab = args.openedTab;
self.usersRemoveOverlay();
self.usersGetData(function(data) {
var dataTemplate = self.usersFormatListData(data),
template = $(monster.template(self, 'users-layout', dataTemplate)),
templateUser;
_.each(dataTemplate.users, function(user) {
templateUser = monster.template(self, 'users-row', user);
template.find('.user-rows').append(templateUser);
});
self.usersBindEvents(template, parent, dataTemplate);
parent
.empty()
.append(template);
if(_userId) {
var cells = parent.find('.grid-row[data-id=' + _userId + '] .grid-cell');
monster.ui.fade(cells);
}
if ( dataTemplate.users.length == 0) {
parent.find('.grid-row.title').css('display', 'none');
parent.find('.no-users-row').css('display', 'block');
} else {
parent.find('.grid-row.title').css('display', 'block');
parent.find('.no-users-row').css('display', 'none');
}
if(_userId && _openedTab) {
template.find('.grid-row[data-id="'+ _userId +'"] .grid-cell[data-type="' + _openedTab + '"]').click();
args.callback && args.callback();
}
});
},
usersFormatUserData: function(dataUser, _mainDirectory, _mainCallflow, _vmbox, _vmboxes) {
var self = this,
formattedUser = {
additionalDevices: 0,
additionalExtensions: 0,
additionalNumbers: 0,
devices: [],
extension: '',
hasFeatures: false,
isAdmin: dataUser.priv_level === 'admin',
listCallerId: [],
listExtensions: [],
listNumbers: [],
phoneNumber: '',
differentEmail: dataUser.email !== dataUser.username,
mapFeatures: {
caller_id: {
icon: 'icon-user',
iconColor: 'icon-blue',
title: self.i18n.active().users.caller_id.title
},
call_forward: {
icon: 'icon-mail-forward',
iconColor: 'icon-yellow',
title: self.i18n.active().users.call_forward.title
},
hotdesk: {
icon: 'icon-fire',
iconColor: 'icon-orange',
title: self.i18n.active().users.hotdesk.title
},
vm_to_email: {
icon: 'icon-telicon-voicemail',
iconColor: 'icon-green',
title: self.i18n.active().users.vm_to_email.title
},
faxing: {
icon: 'icon-telicon-fax',
iconColor: 'icon-red',
title: self.i18n.active().users.faxing.title
},
conferencing: {
icon: 'icon-comments',
iconColor: 'icon-gray',
title: self.i18n.active().users.conferencing.title
},
find_me_follow_me: {
icon: 'icon-sitemap',
iconColor: 'icon-purple',
title: self.i18n.active().users.find_me_follow_me.title
},
music_on_hold: {
icon: 'icon-music',
iconColor: 'icon-pink',
title: self.i18n.active().users.music_on_hold.title
},
call_recording: {
icon: 'icon-microphone',
iconColor: 'icon-blue',
title: self.i18n.active().users.callRecording.title
}
}
};
if(!('extra' in dataUser)) {
dataUser.extra = formattedUser;
}
dataUser.extra.countFeatures = 0;
_.each(dataUser.features, function(v) {
if(v in dataUser.extra.mapFeatures) {
dataUser.extra.countFeatures++;
dataUser.extra.mapFeatures[v].active = true;
}
});
if(dataUser.extra.countFeatures > 0) {
dataUser.extra.hasFeatures = true;
}
if(_mainDirectory) {
dataUser.extra.mainDirectoryId = _mainDirectory.id;
if('directories' in dataUser && _mainDirectory.id in dataUser.directories) {
dataUser.extra.includeInDirectory = true;
}
else {
dataUser.extra.includeInDirectory = false;
}
}
if(_mainCallflow) {
dataUser.extra.mainCallflowId = _mainCallflow.id;
}
if(_vmbox) {
dataUser.extra.vmbox = _vmbox;
}
if(!_.isEmpty(_vmbox) && !_.isEmpty(_vmboxes)) {
var i = _vmboxes.indexOf(_vmbox.mailbox);
_vmboxes.splice(i, 1);
dataUser.extra.existingVmboxes = _vmboxes;
}
dataUser.extra.adminId = self.userId;
return dataUser;
},
usersFormatListData: function(data) {
var self = this,
dataTemplate = {
existingExtensions: [],
countUsers: data.users.length
},
mapUsers = {};
_.each(data.users, function(user) {
mapUsers[user.id] = self.usersFormatUserData(user);
});
_.each(data.callflows, function(callflow) {
if(callflow.type !== 'faxing') {
var userId = callflow.owner_id;
_.each(callflow.numbers, function(number) {
if(number && number.length < 7) {
dataTemplate.existingExtensions.push(number);
}
});
if(userId in mapUsers) {
var user = mapUsers[userId];
//User can only have one phoneNumber and one extension displayed with this code
_.each(callflow.numbers, function(number) {
if(number.length < 7) {
user.extra.listExtensions.push(number);
if(user.extra.extension === '') {
user.extra.extension = number;
}
else {
user.extra.additionalExtensions++;
}
}
else {
user.extra.listCallerId.push(number);
user.extra.listNumbers.push(number);
if(user.extra.phoneNumber === '') {
user.extra.phoneNumber = number;
}
else {
user.extra.additionalNumbers++;
}
}
});
}
}
});
dataTemplate.existingExtensions.sort(self.usersSortExtensions);
_.each(data.devices, function(device) {
var userId = device.owner_id;
if(userId in mapUsers) {
if(mapUsers[userId].extra.devices.length == 2) {
mapUsers[userId].extra.additionalDevices++;
}
else {
mapUsers[userId].extra.devices.push(device.device_type);
}
}
});
var sortedUsers = [];
_.each(mapUsers, function(user) {
sortedUsers.push(user);
});
sortedUsers = monster.util.sort(sortedUsers, 'last_name');
dataTemplate.users = sortedUsers;
return dataTemplate;
},
usersBindEvents: function(template, parent, data) {
var self = this,
currentNumberSearch = '',
currentUser,
currentCallflow,
existingExtensions = data.existingExtensions,
extensionsToSave,
numbersToSave,
toastrMessages = self.i18n.active().users.toastrMessages,
mainDirectoryId,
mainCallflowId,
listUsers = data;
template.find('.grid-row:not(.title) .grid-cell').on('click', function() {
var cell = $(this),
type = cell.data('type'),
row = cell.parents('.grid-row'),
userId = row.data('id');
template.find('.edit-user').slideUp("400", function() {
$(this).empty();
});
if(cell.hasClass('active')) {
template.find('.grid-cell').removeClass('active');
template.find('.grid-row').removeClass('active');
self.usersRemoveOverlay();
cell.css({
'position': 'inline-block',
'z-index': '0'
});
cell.parent().siblings('.edit-user').css({
'position': 'block',
'z-index': '0'
});
}
else {
template.find('.grid-cell').removeClass('active');
template.find('.grid-row').removeClass('active');
cell.toggleClass('active');
row.toggleClass('active');
cell.css({
'position': 'relative',
'z-index': '3'
});
cell.parent().siblings('.edit-user').css({
'position': 'relative',
'z-index': '2'
});
self.usersGetTemplate(type, userId, listUsers, function(template, data) {
if(type === 'name') {
currentUser = data;
template.find('#user_timezone').chosen({search_contains: true, width: "61%"});
data.extra.differentEmail ? template.find('.email-group').show() : template.find('.email-group').hide();
if(data.extra.mainDirectoryId) {
mainDirectoryId = data.extra.mainDirectoryId;
}
if(data.extra.mainCallflowId) {
mainCallflowId = data.extra.mainCallflowId;
}
}
else if(type === 'numbers') {
extensionsToSave = [];
currentCallflow = data.callflow;
_.each(data.extensions, function(number) {
extensionsToSave.push(number);
});
}
else if(type === 'extensions') {
existingExtensions = data.allExtensions;
currentCallflow = data.callflow;
numbersToSave = [];
_.each(data.assignedNumbers, function(v, k) {
numbersToSave.push(k);
});
}
else if(type === 'features') {
currentUser = data;
}
//FancyCheckboxes.
monster.ui.prettyCheck.create(template);
row.find('.edit-user').append(template).slideDown();
$('body').append($('<div id="users_container_overlay"></div>'));
});
}
});
template.find('.users-header .search-query').on('keyup', function() {
var searchString = $(this).val().toLowerCase(),
rows = template.find('.user-rows .grid-row:not(.title)'),
emptySearch = template.find('.user-rows .empty-search-row');
_.each(rows, function(row) {
var row = $(row);
row.data('search').toLowerCase().indexOf(searchString) < 0 ? row.hide() : row.show();
});
if(rows.size() > 0) {
rows.is(':visible') ? emptySearch.hide() : emptySearch.show();
}
});
template.find('.users-header .add-user').on('click', function() {
monster.parallel({
callflows: function(callback) {
self.usersListCallflows(function(callflows) {
callback(null, callflows);
});
},
vmboxes: function(callback) {
self.usersListVMBoxes(function(vmboxes) {
callback(null, vmboxes);
});
}
},
function(err, results) {
var originalData = self.usersFormatAddUser(results),
userTemplate = $(monster.template(self, 'users-creation', originalData));
timezone.populateDropdown(userTemplate.find('#user_creation_timezone'));
monster.ui.prettyCheck.create(userTemplate);
monster.ui.validate(userTemplate.find('#form_user_creation'), {
rules: {
'callflow.extension': {
checkList: originalData.listExtensions
},
'vmbox.number': {
checkList: originalData.listVMBoxes
}
},
messages: {
'user.first_name': {
required: self.i18n.active().validation.required
},
'user.last_name': {
required: self.i18n.active().validation.required
},
'callflow.extension': {
required: self.i18n.active().validation.required
}
}
});
userTemplate.find('#create_user').on('click', function() {
if(monster.ui.valid(userTemplate.find('#form_user_creation'))) {
var dataForm = form2object('form_user_creation'),
formattedData = self.usersFormatCreationData(dataForm);
self.usersCreate(formattedData, function(data) {
popup.dialog('close').remove();
self.usersRender({ userId: data.user.id });
});
}
});
userTemplate.find('#notification_email').on('ifChanged', function() {
userTemplate.find('.email-group').toggleClass('hidden');
});
var popup = monster.ui.dialog(userTemplate, {
title: self.i18n.active().users.dialogCreationUser.title
});
}
);
});
template.on('click', '.cancel-link', function() {
template.find('.edit-user').slideUp("400", function() {
$(this).empty();
template.find('.grid-cell.active').css({
'position': 'inline-block',
'z-index': '0'
});
template.find('.grid-row.active .edit-user').css({
'position': 'block',
'z-index': '0'
});
template.find('.grid-row.active').removeClass('active');
self.usersRemoveOverlay();
template.find('.grid-cell.active').removeClass('active');
});
});
/* Events for Extensions details */
template.on('click', '.save-extensions', function() {
var $this = $(this),
numbers = $.extend(true, [], numbersToSave),
name = $this.parents('.grid-row').find('.grid-cell.name').text(),
userId = $this.parents('.grid-row').data('id');
template.find('.extensions .list-assigned-items .item-row').each(function(k, row) {
var row = $(row),
number;
number = (row.data('id') ? row.data('id') : row.find('.input-extension').val()) + '';
numbers.push(number);
});
self.usersUpdateCallflowNumbers(userId, (currentCallflow || {}).id, numbers, function(callflowData) {
toastr.success(monster.template(self, '!' + toastrMessages.numbersUpdated, { name: name }));
self.usersRender({ userId: callflowData.owner_id });
});
});
template.on('click', '#add_extensions', function() {
var nextExtension = parseInt(self.usersGetNextInt(existingExtensions)) + '',
dataTemplate = {
recommendedExtension: nextExtension
},
newLineTemplate = $(monster.template(self, 'users-newExtension', dataTemplate)),
listExtensions = template.find('.extensions .list-assigned-items');
listExtensions.find('.empty-row').hide();
listExtensions.append(newLineTemplate);
existingExtensions.push(nextExtension);
});
template.on('click', '.remove-extension', function() {
var phoneRow = $(this).parents('.item-row'),
emptyRow = phoneRow.siblings('.empty-row');
if(phoneRow.siblings('.item-row').size() === 0) {
emptyRow.show();
}
phoneRow.remove();
});
template.on('click', '.cancel-extension-link', function() {
var extension = $(this).siblings('input').val(),
index = existingExtensions.indexOf(extension);
if(index > -1) {
existingExtensions.splice(index, 1);
}
$(this).parents('.item-row').remove();
});
/* Events for Users detail */
template.on('click', '#resend_instructions', function() {
var userId = $(this).parents('.grid-row').data('id');
monster.request({
resource: 'voip.users.resendInstructions',
data: {
accountId: self.accountId,
userId: userId
},
success: function(data) {
toastr.success(monster.template(self, '!' + toastrMessages.instructionsSent, { email: currentUser.email }));
}
});
});
template.on('click', '#reset_password', function() {
var userId = $(this).parents('.grid-row').data('id');
monster.request({
resource: 'voip.users.resetPassword',
data: {
accountId: self.accountId,
userId: userId
},
success: function(data) {
toastr.success(monster.template(self, '!' + toastrMessages.passwordReseted, { email: currentUser.email }));
}
});
});
template.on('click', '#delete_user', function() {
var dataUser = $(this).parents('.grid-row').data(),
deleteType = dataUser.priv_level === 'admin' ? 'confirmDeleteAdmin' : 'confirmDeleteUser';
monster.ui.confirm(self.i18n.active().users[deleteType], function() {
self.usersDelete(dataUser.id, function(data) {
toastr.success(monster.template(self, '!' + toastrMessages.userDeleted));
});
});
});
template.on('ifChanged', '#notification_email', function() {
if ( template.find('.email-border').hasClass('open') ) {
template.find('.email-border').removeClass('open', 400);
template.find('.email-group').slideUp();
} else {
template.find('.email-group').slideDown();
template.find('.email-border').addClass('open', 400);
}
});
template.on('click', '.save-user', function() {
var formData = form2object('form-'+currentUser.id),
form = template.find('#form-'+currentUser.id);
monster.util.checkVersion(currentUser, function() {
if(monster.ui.valid(form)) {
currentUser.extra.vmbox.mailbox = formData.extra.vmboxNumber;
currentUser.extra.vmbox.timezone = formData.timezone;
var userToSave = $.extend(true, {}, currentUser, formData);
monster.parallel({
vmbox: function(callback) {
self.usersSmartUpdateVMBox(userToSave, true, function(vmbox) {
callback && callback(null, vmbox);
});
},
user: function(callback) {
self.usersUpdateUser(userToSave, function(userData) {
callback && callback(null, userData.data);
});
}
},
function(error, results) {
toastr.success(monster.template(self, '!' + toastrMessages.userUpdated, { name: results.user.first_name + ' ' + results.user.last_name }));
self.usersRender({ userId: results.user.id });
}
);
}
});
});
template.on('click', '#change_username', function() {
var passwordTemplate = $(monster.template(self, 'users-changePassword', currentUser)),
form = passwordTemplate.find('#form_new_username');
monster.ui.validate(form);
passwordTemplate.find('.save-new-username').on('click', function() {
var formData = form2object('form_new_username'),
userToSave = $.extend(true, {}, currentUser, formData);
if(monster.ui.valid(form)) {
if(!currentUser.extra.differentEmail) {
userToSave.email = userToSave.username;
}
self.usersUpdateUser(userToSave, function(userData) {
currentUser.username = userData.data.username;
template.find('#username').html(userData.data.username);
if(!currentUser.extra.differentEmail) {
template.find('#email').val(userData.data.email);
currentUser.email = userData.username;
}
popup.dialog('close').remove();
toastr.success(monster.template(self, '!' + toastrMessages.userUpdated, { name: userData.data.first_name + ' ' + userData.data.last_name }));
});
}
});
passwordTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
var popup = monster.ui.dialog(passwordTemplate, {
title: self.i18n.active().users.dialogChangePassword.title
});
});
/* Events for Devices in Users */
template.on('click', '.create-device', function() {
var $this = $(this),
type = $this.data('type'),
userId = $this.parents('.grid-row').data('id');
monster.pub('voip.devices.renderAdd', {
type: type,
callback: function(device) {
var rowDevice = monster.template(self, 'users-rowSpareDevice', device),
listAssigned = template.find('.list-assigned-items');
listAssigned.find('.empty-row').hide();
/* reset search */
listAssigned.find('.empty-search-row').hide();
template.find('.unassigned-list-header .search-query').val('');
listAssigned.find('.item-row').show();
/* Add row */
listAssigned.append(rowDevice)
.find('.item-row[data-id="' + device.id + '"]')
.toggleClass('updated')
.find('button')
.removeClass('add-device btn-primary')
.addClass('remove-device btn-danger')
.text(self.i18n.active().remove);
}
});
});
template.on('click', '.save-devices', function() {
var dataDevices = {
new: [],
old: []
},
name = $(this).parents('.grid-row').find('.grid-cell.name').text(),
userId = $(this).parents('.grid-row').data('id');
template.find('.detail-devices .list-assigned-items .item-row.updated').each(function(k, row) {
dataDevices.new.push($(row).data('id'));
});
template.find('.detail-devices .list-unassigned-items .item-row.updated').each(function(k, row) {
dataDevices.old.push($(row).data('id'));
});
self.usersUpdateDevices(dataDevices, userId, function() {
toastr.success(monster.template(self, '!' + toastrMessages.devicesUpdated, { name: name }));
self.usersRender({ userId: userId });
});
});
template.on('click', '.detail-devices .list-unassigned-items .add-device', function() {
var row = $(this).parents('.item-row'),
spare = template.find('.count-spare'),
countSpare = spare.data('count') - 1,
assignedList = template.find('.detail-devices .list-assigned-items');
spare
.html(countSpare)
.data('count', countSpare);
row.toggleClass('updated')
.find('button')
.removeClass('add-device btn-primary')
.addClass('remove-device btn-danger')
.text(self.i18n.active().remove);
assignedList.find('.empty-row').hide();
assignedList.append(row);
var rows = template.find('.list-unassigned-items .item-row');
if(rows.size() === 0) {
template.find('.detail-devices .list-unassigned-items .empty-row').show();
}
else if(rows.is(':visible') === false) {
template.find('.detail-devices .list-unassigned-items .empty-search-row').show();
}
});
template.on('click', '.detail-devices .list-assigned-items .remove-device', function() {
var row = $(this).parents('.item-row'),
spare = template.find('.count-spare'),
countSpare = spare.data('count') + 1,
unassignedList = template.find('.detail-devices .list-unassigned-items');
/* Alter the html */
row.hide();
row.toggleClass('updated')
.find('button')
.removeClass('remove-device btn-danger')
.addClass('add-device btn-primary')
.text(self.i18n.active().add);
unassignedList.append(row);
unassignedList.find('.empty-row').hide();
spare
.html(countSpare)
.data('count', countSpare);
var rows = template.find('.detail-devices .list-assigned-items .item-row');
/* If no rows beside the clicked one, display empty row */
if(rows.is(':visible') === false) {
template.find('.detail-devices .list-assigned-items .empty-row').show();
}
/* If it matches the search string, show it */
if(row.data('search').indexOf(currentNumberSearch) >= 0) {
row.show();
unassignedList.find('.empty-search-row').hide();
}
});
/* Events for Numbers in Users */
template.on('click', '.detail-numbers .list-assigned-items .remove-number', function() {
var $this = $(this),
userName = $this.parents('.grid-row').find('.grid-cell.name').text(),
dataNumbers = $.extend(true, [], extensionsToSave),
userId = $this.parents('.grid-row').data('id'),
row = $this.parents('.item-row');
row.slideUp(function() {
row.remove();
if ( !template.find('.list-assigned-items .item-row').is(':visible') ) {
template.find('.list-assigned-items .empty-row').slideDown();
}
template.find('.item-row').each(function(idx, elem) {
dataNumbers.push($(elem).data('id'));
});
self.usersUpdateCallflowNumbers(userId, (currentCallflow || {}).id, dataNumbers, function(callflowData) {
toastr.success(monster.template(self, '!' + toastrMessages.numbersUpdated, { name: userName }));
self.usersRender({ userId: callflowData.owner_id });
});
});
});
template.on('click', '.callerId-number', function() {
var cnamCell = $(this).parents('.item-row').first(),
phoneNumber = cnamCell.data('id');
if(phoneNumber) {
var args = {
phoneNumber: phoneNumber,
callbacks: {
success: function(data) {
if('cnam' in data.data && data.data.cnam.display_name) {
cnamCell.find('.features i.feature-outbound_cnam').addClass('active');
} else {
cnamCell.find('.features i.feature-outbound_cnam').removeClass('active');
}
if('cnam' in data.data && data.data.cnam.inbound_lookup) {
cnamCell.find('.features i.feature-inbound_cnam').addClass('active');
} else {
cnamCell.find('.features i.feature-inbound_cnam').removeClass('active');
}
}
}
};
monster.pub('common.callerId.renderPopup', args);
}
});
template.on('click', '.e911-number', function() {
var e911Cell = $(this).parents('.item-row').first(),
phoneNumber = e911Cell.data('id');
if(phoneNumber) {
var args = {
phoneNumber: phoneNumber,
callbacks: {
success: function(data) {
if(!($.isEmptyObject(data.data.dash_e911))) {
e911Cell.find('.features i.feature-dash_e911').addClass('active');
}
else {
e911Cell.find('.features i.feature-dash_e911').removeClass('active');
}
}
}
};
monster.pub('common.e911.renderPopup', args);
}
});
template.on('click', '.feature[data-feature="caller_id"]', function() {
self.usersRenderCallerId(currentUser);
});
template.on('click', '.feature[data-feature="call_forward"]', function() {
self.usersRenderCallForward(currentUser);
});
template.on('click', '.feature[data-feature="hotdesk"]', function() {
self.usersRenderHotdesk(currentUser);
});
template.on('click', '.feature[data-feature="find_me_follow_me"]', function() {
monster.parallel({
userDevices: function(callback) {
monster.request({
resource: 'voip.users.listUserDevices',
data: {
accountId: self.accountId,
userId: currentUser.id
},
success: function(data) {
callback(null, data.data);
}
});
},
userCallflow: function(callback) {
self.usersListCallflowsUser(currentUser.id, function(data) {
if(data.length > 0) {
monster.request({
resource: 'voip.users.getCallflow',
data: {
accountId: self.accountId,
callflowId: data[0].id
},
success: function(callflow) {
callback(null, callflow.data)
}
});
} else {
callback(null, null);
}
});
}
},
function(error, results) {
self.usersRenderFindMeFollowMe($.extend(true, results, { currentUser: currentUser }));
}
);
});
template.on('click', '.feature[data-feature="call_recording"]', function() {
self.usersListCallflowsUser(currentUser.id, function(data) {
if(data.length > 0) {
monster.request({
resource: 'voip.users.getCallflow',
data: {
accountId: self.accountId,
callflowId: data[0].id
},
success: function(callflow) {
self.usersRenderCallRecording({
userCallflow: callflow.data,
currentUser: currentUser
});
}
});
} else {
monster.ui.alert('error', self.i18n.active().users.call_recording.noNumber);
}
});
});
template.on('click', '.feature[data-feature="music_on_hold"]', function() {
self.usersRenderMusicOnHold(currentUser);
});
template.on('click', '.feature[data-feature="vm_to_email"]', function() {
self.usersListVMBoxesUser(currentUser.id, function(vmboxes) {
currentUser.extra.deleteAfterNotify = true;
if(vmboxes.length > 0) {
self.usersGetVMBox(vmboxes[0].id, function(data) {
currentUser.extra.deleteAfterNotify = data.delete_after_notify;
self.usersRenderVMToEmail(currentUser);
});
}
else {
self.usersRenderVMToEmail(currentUser);
}
});
});
template.on('click', '.feature[data-feature="conferencing"]', function() {
self.usersGetConferenceFeature(currentUser.id, function(dataConf) {
var data = {
listConferences: dataConf.listConfNumbers,
user: currentUser,
conference: dataConf.conference
};
if(_.isEmpty(data.listConferences)) {
monster.ui.alert('error', self.i18n.active().users.conferencing.noConfNumbers);
}
else {
self.usersRenderConferencing(data);
}
});
});
template.on('click', '.feature[data-feature="faxing"]', function() {
monster.parallel({
numbers: function(callback) {
self.usersListNumbers(function(listNumbers) {
var spareNumbers = {};
_.each(listNumbers.numbers, function(number, key) {
if(number.used_by === '') {
spareNumbers[key] = number;
}
});
callback && callback(null, spareNumbers);
});
},
callflows: function(callback) {
self.usersListCallflowsUser(currentUser.id, function(callflows) {
var existingCallflow;
_.each(callflows, function(callflow) {
if(callflow.type === 'faxing') {
existingCallflow = callflow;
return false;
}
});
if ( existingCallflow ) {
self.callApi({
resource: 'callflow.get',
data: {
accountId: self.accountId,
callflowId: existingCallflow.id
},
success: function(data, status) {
callback && callback(null, data.data);
}
});
} else {
callback && callback(null, existingCallflow);
}
});
}
},
function(err, results) {
results.user = currentUser;
if ( typeof results.callflows !== 'undefined' ) {
self.callApi({
resource: 'faxbox.get',
data: {
accountId: self.accountId,
faxboxId: results.callflows.flow.data.faxbox_id
},
success: function(_data) {
results.faxbox = _data.data;
results.faxbox.id = results.callflows.flow.data.faxbox_id;
self.usersRenderFaxboxes(results);
},
error: function() {
self.usersRenderFaxboxes(results);
}
});
} else {
self.usersRenderFaxboxes(results);
}
}
);
});
template.on('click', '.actions .spare-link:not(.disabled)', function(e) {
e.preventDefault();
var $this = $(this),
args = {
accountName: monster.apps['auth'].currentAccount.name,
accountId: self.accountId,
callback: function(numberList) {
var name = $this.parents('.grid-row').find('.grid-cell.name').text(),
dataNumbers = $.extend(true, [], extensionsToSave),
userId = $this.parents('.grid-row').data('id');
template.find('.empty-row').hide();
template.find('.item-row').each(function(idx, elem) {
dataNumbers.push($(elem).data('id'));
});
_.each(numberList, function(val, idx) {
dataNumbers.push(val.phoneNumber);
template
.find('.list-assigned-items')
.append($(monster.template(self, 'users-numbersItemRow', { number: val })));
});
self.usersUpdateCallflowNumbers(userId, (currentCallflow || {}).id, dataNumbers, function(callflowData) {
toastr.success(monster.template(self, '!' + toastrMessages.numbersUpdated, { name: name }));
self.usersRender({ userId: callflowData.owner_id });
});
}
}
monster.pub('common.numbers.dialogSpare', args);
});
template.on('click', '.actions .buy-link', function(e) {
e.preventDefault();
monster.pub('common.buyNumbers', {
searchType: $(this).data('type'),
callbacks: {
success: function(numbers) {
var countNew = 0;
monster.pub('common.numbers.getListFeatures', function(features) {
_.each(numbers, function(number, k) {
countNew++;
/* Formating number */
number.viewFeatures = $.extend(true, {}, features);
var rowTemplate = monster.template(self, 'users-rowSpareNumber', number);
template.find('.list-unassigned-items .empty-row').hide();
template.find('.list-unassigned-items').append(rowTemplate);
});
var previous = parseInt(template.find('.unassigned-list-header .count-spare').data('count')),
newTotal = previous + countNew;
template.find('.unassigned-list-header .count-spare')
.data('count', newTotal)
.html(newTotal);
template.find('.spare-link.disabled').removeClass('disabled');
});
},
error: function(error) {
}
}
});
});
$('body').on('click', '#users_container_overlay', function() {
template.find('.edit-user').slideUp("400", function() {
$(this).empty();
});
self.usersRemoveOverlay();
template.find('.grid-cell.active').css({
'position': 'inline-block',
'z-index': '0'
});
template.find('.grid-row.active').parent().siblings('.edit-user').css({
'position': 'block',
'z-index': '0'
});
template.find('.grid-cell.active').removeClass('active');
template.find('.grid-row.active').removeClass('active');
});
},
/* Helper function that takes an array of number in parameter, sorts it, and returns the first number not in the array, greater than the minVal */
usersGetNextInt: function(arr) {
var orderedArr = arr,
prevVal = 0,
minVal = 2000,
increment = 1;
orderedArr.sort(function(a,b) {
var parsedA = parseInt(a),
parsedB = parseInt(b);
return parsedA > parsedB ? 1 : -1;
});
_.each(orderedArr, function(val) {
var curr = parseInt(val);
/* If we already stored a previous value */
if(prevVal) {
if(curr - prevVal !== increment) {
return prevVal + increment;
}
}
/* Otherwise, if we didn't, and the current value is greater than the minVal, we return the minVal */
else if(curr > minVal) {
return minVal;
}
/* We don't want to return value lower than our min val, so we only store prevVal that are greater than the minVal */
if(curr >= minVal) {
prevVal = curr;
}
});
return (prevVal) ? prevVal + increment : minVal;
},
usersFormatAddUser: function(data) {
var self = this,
formattedData = {
sendToSameEmail: true,
nextExtension: '',
nextVMBox: '',
listExtensions: {},
listVMBoxes:{},
},
arrayExtensions = [],
arrayVMBoxes = [];
_.each(data.callflows, function(callflow) {
_.each(callflow.numbers, function(number) {
if(number.length < 7) {
formattedData.listExtensions[number] = callflow;
arrayExtensions.push(number);
}
});
});
formattedData.nextExtension = parseInt(self.usersGetNextInt(arrayExtensions)) + '';
_.each(data.vmboxes, function(vmbox) {
formattedData.listVMBoxes[vmbox.mailbox] = vmbox;
arrayVMBoxes.push(vmbox.mailbox);
});
//Set the VMBox Number to 2001 if there are no VMBox in the system, or to the latest vmbox number + 1 if there are
formattedData.nextVMBox = parseInt(self.usersGetNextInt(arrayVMBoxes)) + '';
return formattedData;
},
usersFormatFaxingData: function(data) {
var tempList = [],
listNumbers = {};
_.each(data.numbers, function(val, key){
tempList.push(key);
});
tempList.sort(function(a, b) {
return a < b ? -1 : 1;
});
if(data.callflows) {
if(data.callflows.numbers.length > 0) {
listNumbers[data.callflows.numbers[0]] = data.callflows.numbers[0]
}
}
_.each(tempList, function(val, key) {
listNumbers[val] = val;
});
data.extra = $.extend(true, {}, data.extra, {
listNumbers: listNumbers
});
return data;
},
usersRenderConferencing: function(data) {
var self = this,
data = self.usersFormatConferencingData(data),
featureTemplate = $(monster.template(self, 'users-feature-conferencing', data)),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch(),
featureForm = featureTemplate.find('#conferencing_form');
monster.ui.validate(featureForm);
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
featureTemplate.find('.save').on('click', function() {
var args = {
openedTab: 'features',
callback: function() {
popup.dialog('close').remove();
}
};
if(monster.ui.valid(featureForm)) {
data.conference = form2object('conferencing_form');
if(switchFeature.bootstrapSwitch('status')) {
self.usersUpdateConferencing(data, function(data) {
args.userId = data.user.data.id;
self.usersRender(args);
});
}
else {
self.usersDeleteConferencing(data.user.id, function(data) {
args.userId = data.user.data.id;
self.usersRender(args);
});
}
}
});
monster.ui.prettyCheck.create(featureTemplate.find('.content'));
var popup = monster.ui.dialog(featureTemplate, {
title: data.user.extra.mapFeatures.conferencing.title,
position: ['center', 20]
});
},
usersFormatConferencingData: function(data) {
return data;
},
usersRenderFaxboxes: function(data) {
var self = this,
data = self.usersFormatFaxingData(data),
featureTemplate = $(monster.template(self, 'users-feature-faxing', data)),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch();
monster.ui.prettyCheck.create(featureTemplate.find('.content'));
if ( !_.isEmpty(data.extra.listNumbers) ) {
var popup = monster.ui.dialog(featureTemplate, {
title: data.user.extra.mapFeatures.faxing.title,
position: ['center', 20]
});
} else {
monster.ui.alert('error', self.i18n.active().users.errorNumberFaxing);
}
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
featureTemplate.find('.save').on('click', function() {
var faxboxData = form2object('faxbox_form', '.', true),
args = {
openedTab: 'features',
callback: function() {
popup.dialog('close').remove();
}
};
if ( switchFeature.bootstrapSwitch('status') ) {
faxboxData.owner_id = faxboxData.hasOwnProperty('owner_id') ? faxboxData.owner_id : data.user.id;
if ( data.hasOwnProperty('faxbox') ) {
faxboxData.id = data.faxbox.id;
}
self.usersUpdateFaxing(data, faxboxData, function(results) {
args.userId = results.callflow.owner_id;
self.usersRender(args);
});
} else {
self.usersDeleteFaxing(data.user.id, function() {
args.userId = data.user.id;
self.usersRender(args);
});
}
});
},
usersRenderHotdesk: function(currentUser) {
var self = this,
featureTemplate = $(monster.template(self, 'users-feature-hotdesk', currentUser)),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch(),
requirePin = featureTemplate.find('[name="require_pin"]'),
featureForm = featureTemplate.find('#hotdesk_form');
monster.ui.validate(featureForm);
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
requirePin.on('ifChanged', function() {
if(requirePin.is(':checked')) {
featureTemplate.find('#pin')
.removeAttr('disabled', 'disabled')
.focus();
}
else {
featureTemplate.find('#pin')
.val('')
.attr('disabled', 'disabled');
}
});
featureTemplate.find('.save').on('click', function() {
if(monster.ui.valid(featureForm)) {
var formData = form2object('hotdesk_form'),
args = {
openedTab: 'features',
callback: function() {
popup.dialog('close').remove();
}
};
formData.enabled = switchFeature.bootstrapSwitch('status');
if(formData.require_pin === false) { delete formData.pin; }
delete currentUser.hotdesk;
userToSave = $.extend(true, {}, currentUser, { hotdesk: formData });
self.usersUpdateUser(userToSave, function(data) {
args.userId = data.data.id;
self.usersRender(args);
});
}
});
monster.ui.prettyCheck.create(featureTemplate.find('.content'));
var popup = monster.ui.dialog(featureTemplate, {
title: currentUser.extra.mapFeatures.hotdesk.title,
position: ['center', 20]
});
},
usersRenderVMToEmail: function(currentUser) {
var self = this,
featureTemplate = $(monster.template(self, 'users-feature-vm_to_email', currentUser)),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch(),
featureForm = featureTemplate.find('#vm_to_email_form');
monster.ui.validate(featureForm);
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
featureTemplate.find('.save').on('click', function() {
var formData = form2object('vm_to_email_form'),
userToSave = $.extend(true, {}, currentUser),
enabled = switchFeature.bootstrapSwitch('status'),
args = {
callback: function() {
popup.dialog('close').remove();
},
openedTab: 'features'
},
updateUser = function(user) {
self.usersUpdateUser(user, function(data) {
args.userId = data.data.id;
self.usersRender(args);
});
},
/* updates all the vmboxes with the new delete after notify setting, and then calls the callback*/
updateVMsDeleteAfterNotify = function(val, userId, callbackAfterUpdate) {
self.usersListVMBoxesUser(userId, function(vmboxes) {
var listFnParallel = [];
_.each(vmboxes, function(vm) {
listFnParallel.push(function(callback) {
self.usersGetVMBox(vm.id, function(data) {
/* Only update vms if the deleteAfterNotify value is different than before */
if(data.delete_after_notify !== val) {
data.delete_after_notify = val;
self.usersUpdateVMBox(data, function(data) {
callback(null, data);
});
}
else {
callback(null, data);
}
});
});
});
monster.parallel(listFnParallel, function(err, results) {
callbackAfterUpdate && callbackAfterUpdate(results);
});
});
};
userToSave.vm_to_email_enabled = enabled;
/* Only update the email and the checkboxes if the setting is enabled */
if(enabled === true) {
if(monster.ui.valid(featureForm)) {
userToSave.email = formData.email;
/* Update VMBoxes, then update user and finally close the popup */
updateVMsDeleteAfterNotify(formData.delete_after_notify, userToSave.id, function() {
updateUser(userToSave);
});
}
}
else {
updateUser(userToSave);
}
});
monster.ui.prettyCheck.create(featureTemplate.find('.content'));
var popup = monster.ui.dialog(featureTemplate, {
title: currentUser.extra.mapFeatures.vm_to_email.title,
position: ['center', 20]
});
},
usersRenderCallerId: function(currentUser) {
var self = this,
featureTemplate = $(monster.template(self, 'users-feature-caller_id', currentUser)),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch();
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
featureTemplate.find('.save').on('click', function() {
var switchCallerId = featureTemplate.find('.switch'),
userData = currentUser,
userToSave = $.extend(true, {}, {
caller_id: {
internal: {},
external: {},
}
}, currentUser),
args = {
openedTab: 'features',
callback: function() {
popup.dialog('close').remove();
}
};
if(switchCallerId.bootstrapSwitch('status') === false) {
if('internal' in userToSave.caller_id) {
delete userToSave.caller_id.internal.number;
}
}
else {
var callerIdValue = featureTemplate.find('.caller-id-select').val();
userToSave.caller_id.internal.number = callerIdValue;
userToSave.caller_id.external.number = callerIdValue;
}
self.usersUpdateUser(userToSave, function(data) {
args.userId = data.data.id;
self.usersRender(args);
});
});
if(currentUser.extra.listCallerId.length > 0){
var popup = monster.ui.dialog(featureTemplate, {
title: currentUser.extra.mapFeatures.caller_id.title,
position: ['center', 20]
});
}
else {
monster.ui.alert('error', self.i18n.active().users.errorCallerId);
}
},
usersRenderCallForward: function(currentUser) {
var self = this,
featureTemplate = $(monster.template(self, 'users-feature-call_forward', currentUser)),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch(),
featureForm = featureTemplate.find('#call_forward_form'),
args = {
callback: function() {
popup.dialog('close').remove()
},
openedTab: 'features'
};
monster.ui.validate(featureForm);
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
featureTemplate.find('#phoneType').on('change', function() {
if ( $(this).val() === 'mobile' ) {
featureTemplate.find('#number').mask('+1 (999) 999-9999');
} else if ( $(this).val() === 'deskphone' ) {
featureTemplate.find('#number').mask('(999) 999-9999');
}
});
featureTemplate.find('.save').on('click', function() {
if(monster.ui.valid(featureForm)) {
var formData = form2object('call_forward_form');
formData.enabled = switchFeature.bootstrapSwitch('status');
formData.number = monster.util.unformatPhoneNumber(formData.number, 'keepPlus');
delete formData.phoneType;
var userToSave = $.extend(true, {}, currentUser, { call_forward: formData});
self.usersUpdateUser(userToSave, function(data) {
args.userId = data.data.id;
self.usersRender(args);
});
}
});
monster.ui.prettyCheck.create(featureTemplate.find('.content'));
if ( currentUser.call_forward.number && /^(\+1)/.test(currentUser.call_forward.number) ) {
featureTemplate.find('#phoneType').val('mobile');
featureTemplate.find('#number').mask('+1 (999) 999-9999');
} else {
featureTemplate.find('#phoneType').val('deskphone');
featureTemplate.find('#number').mask('(999) 999-9999');
}
var popup = monster.ui.dialog(featureTemplate, {
title: currentUser.extra.mapFeatures.call_forward.title,
position: ['center', 20]
});
},
usersRenderFindMeFollowMe: function(params) {
var self = this;
if(!params.userCallflow) {
monster.ui.alert('error', self.i18n.active().users.find_me_follow_me.noNumber);
} else if(!params.userDevices || params.userDevices.length === 0) {
monster.ui.alert('error', self.i18n.active().users.find_me_follow_me.noDevice);
} else {
var currentUser = params.currentUser,
userDevices = monster.util.sort(params.userDevices, 'name'),
userCallflow = params.userCallflow,
featureTemplate = $(monster.template(self, 'users-feature-find_me_follow_me', { currentUser: currentUser, devices: userDevices })),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch(),
featureForm = featureTemplate.find('#find_me_follow_me_form'),
args = {
callback: function() {
popup.dialog('close').remove();
},
openedTab: 'features'
},
selectedDevices = {};
if(userCallflow.flow.module === 'ring_group') {
_.each(userCallflow.flow.data.endpoints, function(val) {
selectedDevices[val.id] = val;
});
}
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
featureTemplate.find('.save').on('click', function() {
var enabled = switchFeature.bootstrapSwitch('status'),
enabledDevices = featureTemplate.find('.device-row[data-device_id]:not(.disabled)');
currentUser.smartpbx = currentUser.smartpbx || {};
currentUser.smartpbx.find_me_follow_me = currentUser.smartpbx.find_me_follow_me || {};
currentUser.smartpbx.find_me_follow_me.enabled = (enabled && enabledDevices.length > 0);
if(enabled && enabledDevices.length > 0) {
userCallflow.flow.module = 'ring_group';
userCallflow.flow.data = {
strategy: "simultaneous",
timeout: 20,
endpoints: []
}
$.each(enabledDevices, function() {
var $row = $(this),
deviceId = $row.data('device_id'),
values = $row.find('.slider-time').slider('values');
userCallflow.flow.data.endpoints.push({
id: deviceId,
endpoint_type: "device",
delay: values[0],
timeout: (values[1] - values[0])
});
if(values[1] > userCallflow.flow.data.timeout) { userCallflow.flow.data.timeout = values[1]; }
});
} else {
userCallflow.flow.module = 'user';
userCallflow.flow.data = {
can_call_self: false,
id: currentUser.id,
timeout: 20
}
}
monster.parallel({
callflow: function(callbackParallel) {
self.usersUpdateCallflow(userCallflow, function(data) {
callbackParallel && callbackParallel(null, data.data);
});
},
user: function(callbackParallel) {
self.usersUpdateUser(currentUser, function(data) {
callbackParallel && callbackParallel(null, data.data);
});
}
},
function(err, results) {
args.userId = results.user.id;
self.usersRender(args);
}
);
});
monster.ui.prettyCheck.create(featureTemplate.find('.disable-device'));
var popup = monster.ui.dialog(featureTemplate, {
title: currentUser.extra.mapFeatures.find_me_follow_me.title,
position: ['center', 20]
});
featureTemplate.find('.disable-device').on('ifToggled', function() {
var parentRow = $(this).parents('.device-row');
if(this.checked) {
parentRow.find('.times').stop().animate({ opacity: 0 });
parentRow.addClass('disabled')
} else {
parentRow.find('.times').stop().animate({ opacity: 1 });
parentRow.removeClass('disabled')
}
});
featureTemplate.find('.distribute-button').on('click', function() {
var sliders = featureTemplate.find('.slider-time')
max = sliders.first().slider('option', 'max'),
section = Math.floor(max/sliders.length),
current = 0;
monster.ui.prettyCheck.action(featureTemplate.find('.device-row .disable-device'), 'uncheck');
$.each(sliders, function() {
$(this).slider('values', [current, current+=section]);
});
});
featureTemplate.on('click', '.device-row.title .scale-max', function() {
var $this = $(this),
input = $this.siblings('.scale-max-input');
input.show();
input.focus();
$this.hide();
});
featureTemplate.on('blur', '.device-row.title .scale-max-input', function(e) {
var $this = $(this),
value = $this.val(),
intValue = parseInt($this.val());
if(value != $this.data('current') && !isNaN(intValue) && intValue >= 30) {
self.usersRenderFindMeFollowMeSliders(featureTemplate, userDevices, selectedDevices, intValue);
} else {
$this.val($this.data('current')).hide();
$this.siblings('.scale-max').show();
}
});
featureTemplate.on('keydown', '.device-row.title .scale-max-input', function(e) {
switch(e.keyCode) {
case 27:
$(this).val(-1);
case 13:
e.preventDefault();
$(this).blur();
break;
}
});
self.usersRenderFindMeFollowMeSliders(featureTemplate, userDevices, selectedDevices);
}
},
usersRenderFindMeFollowMeSliders: function(template, deviceList, ringGroup, maxSeconds) {
var self = this,
scaleSections = 6, //Number of 'sections' in the time scales for the sliders
scaleMaxSeconds = maxSeconds && maxSeconds >= 30 ? maxSeconds : 120; //Maximum of seconds, corresponding to the end of the scale
if(!maxSeconds) {
var currentMax = 0;
_.each(ringGroup, function(endpoint) {
currentMax = (endpoint.delay+endpoint.timeout > currentMax) ? endpoint.delay+endpoint.timeout : currentMax;
});
scaleMaxSeconds = currentMax > scaleMaxSeconds ? Math.ceil(currentMax/60)*60 : scaleMaxSeconds;
}
var sliderTooltip = function(event, ui) {
var val = ui.value,
tooltip = '<div class="slider-tooltip"><div class="slider-tooltip-inner">' + val + '</div></div>';
$(ui.handle).html(tooltip);
},
createTooltip = function(event, ui, deviceId, sliderObj) {
var val1 = sliderObj.slider('values', 0),
val2 = sliderObj.slider('values', 1),
tooltip1 = '<div class="slider-tooltip"><div class="slider-tooltip-inner">' + val1 + '</div></div>',
tooltip2 = '<div class="slider-tooltip"><div class="slider-tooltip-inner">' + val2 + '</div></div>';
template.find('.device-row[data-device_id="'+ deviceId + '"] .slider-time .ui-slider-handle').first().html(tooltip1);
template.find('.device-row[data-device_id="'+ deviceId + '"] .slider-time .ui-slider-handle').last().html(tooltip2);
},
createSlider = function(device) {
var deviceRow = template.find('.device-row[data-device_id="'+ device.id +'"]');
deviceRow.find('.slider-time').slider({
range: true,
min: 0,
max: scaleMaxSeconds,
values: device.id in ringGroup ? [ ringGroup[device.id].delay, ringGroup[device.id].delay+ringGroup[device.id].timeout ] : [0,0],
slide: sliderTooltip,
change: sliderTooltip,
create: function(event, ui) {
createTooltip(event, ui, device.id, $(this));
},
});
createSliderScale(deviceRow);
},
createSliderScale = function(container, isHeader) {
var scaleContainer = container.find('.scale-container')
isHeader = isHeader || false;
scaleContainer.empty();
for(var i=1; i<=scaleSections; i++) {
var toAppend = '<div class="scale-element" style="width:'+(100/scaleSections)+'%;">'
+ (isHeader
? (i==scaleSections
? '<input type="text" value="'+scaleMaxSeconds+'" data-current="'+scaleMaxSeconds+'" class="scale-max-input" maxlength="3"><span class="scale-max">'
:'<span>')
+ Math.floor(i*scaleMaxSeconds/scaleSections) + ' Sec</span>'
: '')
+ '</div>';
scaleContainer.append(toAppend);
}
if(isHeader) {
scaleContainer.append('<span>0 Sec</span>');
}
};
_.each(deviceList, function(device) {
createSlider(device);
if(!(device.id in ringGroup)) {
monster.ui.prettyCheck.action(template.find('.device-row[data-device_id="'+device.id+'"] .disable-device'), 'check');
}
});
createSliderScale(template.find('.device-row.title'), true);
},
usersRenderCallRecording: function(params) {
var self = this,
templateData = $.extend(true, {
user: params.currentUser
},
(params.currentUser.extra.mapFeatures.call_recording.active ? {
url: params.userCallflow.flow.data.url,
format: params.userCallflow.flow.data.format,
timeLimit: params.userCallflow.flow.data.time_limit
} : {})
),
featureTemplate = $(monster.template(self, 'users-feature-call_recording', templateData)),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch(),
featureForm = featureTemplate.find('#call_recording_form'),
popup;
monster.ui.validate(featureForm, {
rules: {
'time_limit': {
digits: true
}
}
});
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
featureTemplate.find('.save').on('click', function() {
if(monster.ui.valid(featureForm)) {
var formData = form2object('call_recording_form'),
enabled = switchFeature.bootstrapSwitch('status');
if(!('smartpbx' in params.currentUser)) { params.currentUser.smartpbx = {}; }
if(!('call_recording' in params.currentUser.smartpbx)) {
params.currentUser.smartpbx.call_recording = {
enabled: false
};
}
if(params.currentUser.smartpbx.call_recording.enabled || enabled) {
params.currentUser.smartpbx.call_recording.enabled = enabled;
var newCallflow = $.extend(true, {}, params.userCallflow);
if(enabled) {
if(newCallflow.flow.module === 'record_call') {
newCallflow.flow.data = $.extend(true, { action: "start" }, formData);
} else {
newCallflow.flow = {
children: {
"_": $.extend(true, {}, params.userCallflow.flow)
},
module: "record_call",
data: $.extend(true, { action: "start" }, formData)
}
var flow = newCallflow.flow;
while(flow.children && '_' in flow.children) {
if(flow.children['_'].module === 'record_call' && flow.children['_'].data.action === 'stop') {
break; // If there is already a Stop Record Call
} else if(flow.children['_'].module === 'voicemail') {
var voicemailNode = $.extend(true, {}, flow.children['_']);
flow.children['_'] = {
module: 'record_call',
data: { action: "stop" },
children: { '_': voicemailNode }
}
break;
} else {
flow = flow.children['_'];
}
}
}
} else {
newCallflow.flow = $.extend(true, {}, params.userCallflow.flow.children["_"]);
var flow = newCallflow.flow;
while(flow.children && '_' in flow.children) {
if(flow.children['_'].module === 'record_call') {
flow.children = flow.children['_'].children;
break;
} else {
flow = flow.children['_'];
}
}
}
self.usersUpdateCallflow(newCallflow, function(updatedCallflow) {
self.usersUpdateUser(params.currentUser, function(updatedUser) {
popup.dialog('close').remove();
self.usersRender({ userId: params.currentUser.id });
});
});
} else {
popup.dialog('close').remove();
self.usersRender({ groupId: params.currentUser.id });
}
}
});
popup = monster.ui.dialog(featureTemplate, {
title: params.currentUser.extra.mapFeatures.call_recording.title,
position: ['center', 20]
});
},
usersRenderMusicOnHold: function(currentUser) {
var self = this,
silenceMediaId = 'silence_stream://300000';
self.usersListMedias(function(medias) {
var templateData = {
user: currentUser,
silenceMedia: silenceMediaId,
mediaList: medias,
media: 'music_on_hold' in currentUser && 'media_id' in currentUser.music_on_hold ? currentUser.music_on_hold.media_id : silenceMediaId
},
featureTemplate = $(monster.template(self, 'users-feature-music_on_hold', templateData)),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch(),
popup,
closeUploadDiv = function(newMedia) {
var uploadInput = featureTemplate.find('.upload-input');
uploadInput.wrap('<form>').closest('form').get(0).reset();
uploadInput.unwrap();
featureTemplate.find('.upload-div').slideUp(function() {
featureTemplate.find('.upload-toggle').removeClass('active');
});
if(newMedia) {
var mediaSelect = featureTemplate.find('.media-dropdown');
mediaSelect.append('<option value="'+newMedia.id+'">'+newMedia.name+'</option>');
mediaSelect.val(newMedia.id);
}
};
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
featureTemplate.find('.upload-toggle').on('click', function() {
if($(this).hasClass('active')) {
featureTemplate.find('.upload-div').stop(true, true).slideUp();
} else {
featureTemplate.find('.upload-div').stop(true, true).slideDown();
}
});
featureTemplate.find('.upload-cancel').on('click', function() {
closeUploadDiv();
});
featureTemplate.find('.upload-submit').on('click', function() {
var file = featureTemplate.find('.upload-input')[0].files[0];
fileReader = new FileReader();
fileReader.onloadend = function(evt) {
monster.request({
resource: 'voip.users.createMedia',
data: {
accountId: self.accountId,
data: {
streamable: true,
name: file.name,
media_source: "upload",
description: file.name
}
},
success: function(data, status) {
var media = data.data;
monster.request({
resource: 'voip.users.uploadMedia',
data: {
accountId: self.accountId,
mediaId: media.id,
data: evt.target.result
},
success: function(data, status) {
closeUploadDiv(media);
},
error: function(data, status) {
monster.request({
resource: 'voip.users.deleteMedia',
data: {
accountId: self.accountId,
mediaId: media.id,
data: {}
},
success: function(data, status) {
}
});
}
});
}
});
};
if(file) {
if(file.size >= (Math.pow(2,20) * 5)) { //If size bigger than 5MB
monster.ui.alert(self.i18n.active().users.music_on_hold.fileTooBigAlert);
} else {
fileReader.readAsDataURL(file);
}
} else {
monster.ui.alert(self.i18n.active().users.music_on_hold.emptyUploadAlert);
}
});
featureTemplate.find('.save').on('click', function() {
var selectedMedia = featureTemplate.find('.media-dropdown option:selected').val(),
enabled = switchFeature.bootstrapSwitch('status');
if(!('music_on_hold' in currentUser)) {
currentUser.music_on_hold = {};
}
if('media_id' in currentUser.music_on_hold || enabled) {
if(enabled) {
currentUser.music_on_hold = {
media_id: selectedMedia
};
} else {
currentUser.music_on_hold = {};
}
self.usersUpdateUser(currentUser, function(updatedUser) {
popup.dialog('close').remove();
self.usersRender({ userId: currentUser.id });
});
} else {
popup.dialog('close').remove();
self.usersRender({ userId: currentUser.id });
}
});
popup = monster.ui.dialog(featureTemplate, {
title: currentUser.extra.mapFeatures.music_on_hold.title,
position: ['center', 20]
});
});
},
usersCleanUserData: function(userData) {
var userData = $.extend(true, {}, userData),
fullName = userData.first_name + ' ' + userData.last_name,
defaultCallerIdName = fullName.substring(0, 15),
defaults = {
caller_id: {
internal: {
name: defaultCallerIdName
},
external: {
name: defaultCallerIdName
}
}
};
userData = $.extend(true, defaults, userData);
/* If the user has been removed from the directory */
if(userData.extra) {
if(userData.extra.includeInDirectory === false) {
if('directories' in userData && userData.extra.mainDirectoryId && userData.extra.mainDirectoryId in userData.directories) {
delete userData.directories[userData.extra.mainDirectoryId];
}
}
else {
userData.directories = userData.directories || {};
if(userData.extra.mainCallflowId) {
userData.directories[userData.extra.mainDirectoryId] = userData.extra.mainCallflowId;
}
}
if('differentEmail' in userData.extra) {
userData.email = userData.extra.differentEmail ? userData.extra.email : userData.username;
}
if('language' in userData.extra) {
if(userData.extra.language !== 'auto') {
userData.language = userData.extra.language;
}
else {
delete userData.language;
}
}
}
delete userData.include_directory;
delete userData.features;
delete userData.extra;
delete userData[''];
return userData;
},
usersGetTemplate: function(type, userId, listUsers, callbackAfterData) {
var self = this,
template;
if(type === 'name') {
self.usersGetNameTemplate(userId, listUsers, callbackAfterData);
}
else if(type === 'numbers') {
self.usersGetNumbersTemplate(userId, callbackAfterData);
}
else if(type === 'extensions') {
self.usersGetExtensionsTemplate(userId, callbackAfterData);
}
else if(type === 'features') {
self.usersGetFeaturesTemplate(userId, listUsers, callbackAfterData);
}
else if(type === 'devices') {
self.usersGetDevicesTemplate(userId, callbackAfterData);
}
},
usersGetFeaturesTemplate: function(userId, listUsers, callback) {
var self = this;
self.usersGetUser(userId, function(userData) {
_.each(listUsers.users, function(user) {
if(user.id === userData.id) {
userData = $.extend(true, userData, user);
}
});
var dataTemplate = self.usersFormatUserData(userData);
template = $(monster.template(self, 'users-features', dataTemplate));
callback && callback(template, dataTemplate);
});
},
usersGetNameTemplate: function(userId, listUsers, callbackAfterFormat) {
var self = this;
monster.parallel({
mainCallflow: function(callback) {
self.usersGetMainCallflow(userId, function(mainCallflow) {
callback(null, mainCallflow);
});
},
mainDirectory: function(callback) {
self.usersGetMainDirectory(function(mainDirectory) {
callback(null, mainDirectory);
});
},
user: function(callback) {
self.usersGetUser(userId, function(userData) {
callback(null, userData);
});
},
vmbox: function(callback) {
self.usersListVMBoxesUser(userId, function(vmboxes) {
if(vmboxes.length > 0) {
self.usersGetVMBox(vmboxes[0].id, function(vmbox) {
callback(null, vmbox);
});
}
else {
callback(null, {});
}
});
},
existingVmboxes: function(callback) {
self.usersListVMBoxes(function(vmboxes) {
var listVMBoxes = [];
_.each(vmboxes, function(vmbox) {
listVMBoxes.push(vmbox.mailbox);
});
callback(null, listVMBoxes);
});
}
},
function(error, results) {
var userData = results.user;
_.each(listUsers.users, function(user) {
if(user.id === results.user.id) {
userData = $.extend(true, user, userData);
return false;
}
});
var dataTemplate = self.usersFormatUserData(userData, results.mainDirectory, results.mainCallflow, results.vmbox, results.existingVmboxes);
template = $(monster.template(self, 'users-name', dataTemplate));
monster.ui.validate(template.find('form.user-fields'), {
rules: {
'extra.vmboxNumber': {
checkList: dataTemplate.extra.existingVmboxes
}
},
messages: {
'first_name': {
required: self.i18n.active().validation.required
},
'last_name': {
required: self.i18n.active().validation.required
}
}
});
timezone.populateDropdown(template.find('#user_timezone'), dataTemplate.timezone);
callbackAfterFormat && callbackAfterFormat(template, dataTemplate);
}
);
},
usersGetDevicesData: function(callback) {
var self = this;
monster.request({
resource: 'voip.users.listDevices',
data: {
accountId: self.accountId
},
success: function(data) {
callback && callback(data.data);
}
});
},
usersGetNumbersData: function(userId, callback) {
var self = this;
monster.parallel({
callflow: function(callbackParallel) {
var response = {};
self.usersListCallflows(function(callflows) {
response.list = callflows;
var callflowId;
$.each(callflows, function(k, callflowLoop) {
/* Find Smart PBX Callflow of this user */
if(callflowLoop.owner_id === userId && callflowLoop.type !== 'faxing') {
callflowId = callflowLoop.id;
return false;
}
});
if(callflowId) {
monster.request({
resource: 'voip.users.getCallflow',
data: {
accountId: self.accountId,
callflowId: callflowId
},
success: function(callflow) {
response.userCallflow = callflow.data;
callbackParallel && callbackParallel(null, response);
}
});
}
else {
callbackParallel && callbackParallel(null, response);
}
});
},
numbers: function(callbackParallel) {
self.usersListNumbers(function(listNumbers) {
callbackParallel && callbackParallel(null, listNumbers);
});
}
},
function(err, results) {
callback && callback(results);
}
);
},
usersGetNumbersTemplate: function(userId, callback) {
var self = this;
self.usersGetNumbersData(userId, function(results) {
self.usersFormatNumbersData(userId, results, function(results) {
template = $(monster.template(self, 'users-numbers', results));
callback && callback(template, results);
});
});
},
usersGetDevicesTemplate: function(userId, callback) {
var self = this;
self.usersGetDevicesData(function(results) {
var results = self.usersFormatDevicesData(userId, results);
template = $(monster.template(self, 'users-devices', results));
callback && callback(template, results);
});
},
usersGetExtensionsTemplate: function(userId, callback) {
var self = this;
self.usersGetNumbersData(userId, function(results) {
self.usersFormatNumbersData(userId, results, function(results) {
template = $(monster.template(self, 'users-extensions', results));
callback && callback(template, results);
});
});
},
usersFormatDevicesData: function(userId, data) {
var self = this,
formattedData = {
countSpare: 0,
assignedDevices: {},
unassignedDevices: {}
};
_.each(data, function(device) {
if(device.owner_id === userId) {
formattedData.assignedDevices[device.id] = device;
}
else if(device.owner_id === '' || !('owner_id' in device)) {
formattedData.countSpare++;
formattedData.unassignedDevices[device.id] = device;
}
});
formattedData.emptyAssigned = _.isEmpty(formattedData.assignedDevices);
formattedData.emptySpare = _.isEmpty(formattedData.unassignedDevices);
return formattedData;
},
usersFormatNumbersData: function(userId, data, callback) {
var self = this,
response = {
countSpare: 0,
assignedNumbers: [],
unassignedNumbers: {},
callflow: data.callflow.userCallflow,
extensions: []
};
monster.pub('common.numbers.getListFeatures', function(features) {
if('numbers' in data.numbers) {
_.each(data.numbers.numbers, function(number, k) {
/* Formating number */
number.viewFeatures = $.extend(true, {}, features);
/* TODO: Once locality is enabled, we need to remove it */
number.localityEnabled = 'locality' in number ? true : false;
_.each(number.features, function(feature) {
if(feature in number.viewFeatures) {
number.viewFeatures[feature].active = 'active';
}
});
/* Adding to spare numbers */
if(number.used_by === '') {
response.countSpare++;
response.unassignedNumbers[k] = number;
}
});
}
if(response.callflow) {
/* If a number is in a callflow and is returned by the phone_numbers, add it to the assigned numbers */
_.each(response.callflow.numbers, function(number) {
if(number in data.numbers.numbers) {
var numberElement = data.numbers.numbers[number];
numberElement.phoneNumber = number;
response.assignedNumbers.push(numberElement);
}
else {
response.extensions.push(number);
}
});
}
response.assignedNumbers = monster.util.sort(response.assignedNumbers, 'phoneNumber');
/* List of extensions */
response.allExtensions = [];
_.each(data.callflow.list, function(callflow) {
_.each(callflow.numbers, function(number) {
/* If it's a valid extension number (ie: a number that's not in the number database) */
if(!(number in data.numbers.numbers) && !(_.isNaN(parseInt(number)))) {
response.allExtensions.push(number);
}
});
});
/* Sort extensions so that we can recommend an available extension to a user whom would add a new one */
response.allExtensions.sort(function(a, b) {
var parsedA = parseInt(a),
parsedB = parseInt(b),
result = -1;
if(parsedA > 0 && parsedB > 0) {
result = parsedA > parsedB;
}
return result;
});
response.emptyAssigned = _.isEmpty(response.assignedNumbers);
response.emptySpare = _.isEmpty(response.unassignedNumbers);
response.emptyExtensions = _.isEmpty(response.extensions);
callback && callback(response);
});
},
usersFormatCreationData: function(data, callback) {
var self = this,
fullName = data.user.first_name + ' ' + data.user.last_name,
callerIdName = fullName.substring(0, 15),
defaultTimezone = timezone.getLocaleTimezone(),
formattedData = {
user: $.extend(true, {}, {
caller_id: {
internal: {
name: callerIdName
},
external: {
name: callerIdName
}
},
email: data.extra.differentEmail ? data.extra.email : data.user.username,
priv_level: 'user',
timezone: defaultTimezone
}, data.user),
vmbox: {
//mailbox: (data.callflow || {}).extension,
mailbox: data.vmbox.number,
name: fullName + '\'s VMBox',
timezone: defaultTimezone
},
callflow: {
contact_list: {
exclude: false
},
flow: {
children: {
_: {
children: {},
data: {},
module: 'voicemail'
}
},
data: {
can_call_self: false,
timeout: 20
},
module: 'user'
},
name: fullName + ' SmartPBX\'s Callflow',
numbers: [ (data.callflow || {}).extension ]
},
extra: data.extra
};
return formattedData;
},
/* Utils */
usersDelete: function(userId, callback) {
var self = this;
monster.parallel({
devices: function(callback) {
monster.request({
resource: 'voip.users.listUserDevices',
data: {
accountId: self.accountId,
userId: userId
},
success: function(data) {
callback(null, data.data);
}
});
},
vmbox: function(callback) {
self.usersListVMBoxesUser(userId, function(data) {
callback(null, data);
});
},
callflows: function(callback) {
self.usersListCallflowsUser(userId, function(data) {
callback(null, data);
});
}
},
function(error, results) {
var listFnDelete = [];
_.each(results.devices, function(device) {
listFnDelete.push(function(callback) {
// self.usersDeleteDevice(device.id, function(data) {
self.usersUnassignDevice(device.id, function(data) {
callback(null, '');
});
});
});
_.each(results.callflows, function(callflow) {
listFnDelete.push(function(callback) {
self.usersDeleteCallflow(callflow.id, function(data) {
callback(null, '');
});
});
});
_.each(results.vmbox, function(vmbox) {
listFnDelete.push(function(callback) {
self.usersDeleteVMBox(vmbox.id, function(data) {
callback(null, '');
});
});
});
monster.parallel(listFnDelete, function(err, resultsDelete) {
self.usersDeleteUser(userId, function(data) {
toastr.success(monster.template(self, '!' + self.i18n.active().users.toastrMessages.userDelete, { name: data.first_name + ' ' + data.last_name }));
self.usersRender();
});
});
}
);
},
usersDeleteUser: function(userId, callback) {
var self = this;
monster.request({
resource: 'voip.users.deleteUser',
data: {
userId: userId,
accountId: self.accountId,
data: {}
},
success: function(data) {
callback(data.data);
}
});
},
usersDeleteVMBox: function(vmboxId, callback) {
var self = this;
monster.request({
resource: 'voip.users.deleteVMBox',
data: {
vmboxId: vmboxId,
accountId: self.accountId,
data: {}
},
success: function(data) {
callback(data.data);
}
});
},
usersUnassignDevice: function(deviceId, callback) {
var self = this;
self.usersGetDevice(deviceId, function(deviceGet) {
delete deviceGet.owner_id;
self.usersUpdateDevice(deviceGet, function(updatedDevice) {
callback && callback(updatedDevice);
});
});
},
usersDeleteDevice: function(deviceId, callback) {
var self = this;
monster.request({
resource: 'voip.users.deleteDevice',
data: {
deviceId: deviceId,
accountId: self.accountId,
data: {}
},
success: function(data) {
callback(data.data);
}
});
},
usersDeleteCallflow: function(callflowId, callback) {
var self = this;
monster.request({
resource: 'voip.users.deleteCallflow',
data: {
callflowId: callflowId,
accountId: self.accountId,
data: {}
},
success: function(data) {
callback(data.data);
}
});
},
usersCreate: function(data, callback) {
var self = this;
monster.request({
resource: 'voip.users.createUser',
data: {
accountId: self.accountId,
data: data.user
},
success: function(_dataUser) {
var userId = _dataUser.data.id;
data.user.id = userId;
data.vmbox.owner_id = userId;
self.usersCreateVMBox(data.vmbox, function(_dataVM) {
data.callflow.owner_id = userId;
data.callflow.flow.data.id = userId;
data.callflow.flow.children['_'].data.id = _dataVM.id;
self.usersCreateCallflow(data.callflow, function(_dataCF) {
if(data.extra.includeInDirectory) {
self.usersAddUserToMainDirectory(_dataUser.data, _dataCF.id, function(dataDirectory) {
callback(data);
});
}
else {
callback(data);
}
});
});
}
});
},
/* Hack to support users from previous version */
usersMigrateFromExtensions: function(userId, listExtensions, callback) {
var self = this;
self.usersGetUser(userId, function(user) {
user.extra = {
vmbox: {
mailbox: listExtensions[0]
}
};
var fullName = user.first_name + ' ' + user.last_name,
callflow = {
contact_list: {
exclude: false
},
flow: {
children: {
_: {
children: {},
data: {
},
module: 'voicemail'
}
},
data: {
id: user.id,
can_call_self: false,
timeout: 20
},
module: 'user'
},
name: fullName + ' SmartPBX\'s Callflow',
numbers: listExtensions,
owner_id: user.id
};
self.usersSmartUpdateVMBox(user, false, function(_dataVM) {
callflow.flow.children['_'].data.id = _dataVM.id;
self.usersCreateCallflow(callflow, function(_dataCF) {
callback && callback(_dataCF);
});
});
});
},
usersAddUserToMainDirectory: function(dataUser, callflowId, callback) {
var self = this;
self.usersGetMainDirectory(function(directory) {
dataUser.directories = dataUser.directories || {};
dataUser.directories[directory.id] = callflowId;
self.usersUpdateUser(dataUser, function(data) {
callback && callback(data);
});
});
},
usersGetMainCallflow: function(userId, callback) {
var self = this;
self.usersListCallflowsUser(userId, function(listCallflows) {
var indexMain = -1;
_.each(listCallflows, function(callflow, index) {
if(callflow.owner_id === userId) {
indexMain = index;
return false;
}
});
if(indexMain === -1) {
//toastr.error(self.i18n.active().users.noUserCallflow);
callback(null);
}
else {
callback(listCallflows[indexMain]);
}
});
},
usersGetMainDirectory: function(callback) {
var self = this;
self.usersListDirectories(function(listDirectories) {
var indexMain = -1;
_.each(listDirectories, function(directory, index) {
if(directory.name === 'SmartPBX Directory') {
indexMain = index;
return false;
}
});
if(indexMain === -1) {
self.usersCreateMainDirectory(function(data) {
callback(data);
});
}
else {
callback(listDirectories[indexMain]);
}
});
},
usersListDirectories: function(callback) {
var self = this;
monster.request({
resource: 'voip.users.listDirectories',
data: {
accountId: self.accountId
},
success: function(data) {
callback && callback(data.data);
}
});
},
usersCreateMainDirectory: function(callback) {
var self = this,
dataDirectory = {
confirm_match: false,
max_dtmf: '0',
min_dtmf: '3',
name: 'SmartPBX Directory',
sort_by: 'last_name'
};
monster.request({
resource: 'voip.users.createDirectory',
data: {
accountId: self.accountId,
data: dataDirectory
},
success: function(data) {
callback && callback(data.data);
}
});
},
usersListCallflows: function(callback) {
var self = this;
monster.request({
resource: 'voip.users.getCallflows',
data: {
accountId: self.accountId
},
success: function(data) {
callback(data.data);
}
});
},
usersListCallflowsUser: function(userId, callback) {
var self = this;
monster.request({
resource: 'voip.users.listUserCallflows',
data: {
accountId: self.accountId,
userId: userId
},
success: function(data) {
callback(data.data);
}
});
},
usersListVMBoxes: function(callback) {
var self = this;
monster.request({
resource: 'voip.users.listVMBoxes',
data: {
accountId: self.accountId
},
success: function(data) {
callback(data.data);
}
});
},
usersListVMBoxesUser: function(userId, callback) {
var self = this;
monster.request({
resource: 'voip.users.listUserVMBoxes',
data: {
accountId: self.accountId,
userId: userId
},
success: function(data) {
callback(data.data);
}
});
},
usersGetVMBox: function(vmboxId, callback) {
var self = this;
monster.request({
resource: 'voip.users.getVMBox',
data: {
accountId: self.accountId,
vmboxId: vmboxId
},
success: function(data) {
callback(data.data);
}
});
},
usersCreateVMBox: function(vmData, callback) {
var self = this;
monster.request({
resource: 'voip.users.createVMBox',
data: {
accountId: self.accountId,
data: vmData
},
success: function(data) {
callback(data.data);
}
});
},
usersUpdateVMBox: function(vmData, callback) {
var self = this;
monster.request({
resource: 'voip.users.updateVMBox',
data: {
accountId: self.accountId,
data: vmData,
vmboxId: vmData.id
},
success: function(data) {
callback(data.data);
}
});
},
usersCreateCallflow: function(callflowData, callback) {
var self = this;
monster.request({
resource: 'voip.users.createCallflow',
data: {
accountId: self.accountId,
data: callflowData
},
success: function(data) {
callback(data.data);
}
});
},
usersGetUser: function(userId, callback) {
var self = this;
monster.request({
resource: 'voip.users.getUser',
data: {
accountId: self.accountId,
userId: userId
},
success: function(user) {
callback && callback(user.data);
}
});
},
usersUpdateUser: function(userData, callback) {
var self = this;
userData = self.usersCleanUserData(userData);
monster.request({
resource: 'voip.users.updateUser',
data: {
accountId: self.accountId,
userId: userData.id,
data: userData
},
success: function(userData) {
callback && callback(userData);
}
});
},
usersGetConferenceFeature: function(userId, globalCallback) {
var self = this,
dataResponse = {
conference: {},
listConfNumbers: []
};
monster.parallel({
confNumbers: function(callback) {
self.usersListConfNumbers(function(numbers) {
callback && callback(null, numbers);
});
},
listConferences: function(callback) {
self.usersListConferences(userId, function(conferences) {
if(conferences.length > 0) {
self.usersGetConference(conferences[0].id, function(conference) {
callback && callback(null, conference);
});
}
else {
callback && callback(null, {});
}
});
}
},
function(err, results) {
dataResponse.conference = results.listConferences;
dataResponse.listConfNumbers = results.confNumbers;
globalCallback && globalCallback(dataResponse);
}
);
},
usersListConfNumbers: function(callback) {
var self = this;
monster.request({
resource: 'voip.users.listConfNumbers',
data: {
accountId: self.accountId
},
success: function(data) {
var numbers = [];
_.each(data.data, function(conf) {
if(conf.name === 'MainConference') {
if(conf.numbers.length > 0 && conf.numbers[0] !== 'undefinedconf') {
numbers = numbers.concat(conf.numbers);
}
}
});
callback && callback(numbers);
}
});
},
usersListConferences: function(userId, callback) {
var self = this;
monster.request({
resource: 'voip.users.listUserConferences',
data: {
accountId: self.accountId,
userId: userId
},
success: function(data) {
callback(data.data);
}
});
},
usersGetConference: function(conferenceId, callback) {
var self = this;
monster.request({
resource: 'voip.users.getConference',
data: {
accountId: self.accountId,
conferenceId: conferenceId
},
success: function(data) {
callback(data.data);
}
});
},
usersUpdateConference: function(conference, callback) {
var self = this;
monster.request({
resource: 'voip.users.updateConference',
data: {
accountId: self.accountId,
conferenceId: conference.id,
data: conference
},
success: function(data) {
callback(data.data);
}
});
},
usersCreateConference: function(conference, callback) {
var self = this;
monster.request({
resource: 'voip.users.createConference',
data: {
accountId: self.accountId,
data: conference
},
success: function(data) {
callback(data.data);
}
});
},
usersDeleteConference: function(conferenceId, callback) {
var self = this;
monster.request({
resource: 'voip.users.deleteConference',
data: {
accountId: self.accountId,
conferenceId: conferenceId,
data: {}
},
success: function(data) {
callback(data.data);
}
});
},
usersGetDevice: function(deviceId, callback) {
var self = this;
monster.request({
resource: 'voip.users.getDevice',
data: {
accountId: self.accountId,
deviceId: deviceId
},
success: function(data) {
callback(data.data);
}
});
},
usersUpdateDevice: function(data, callback) {
var self = this;
monster.request({
resource: 'voip.users.updateDevice',
data: {
accountId: self.accountId,
data: data,
deviceId: data.id
},
success: function(data) {
callback(data.data);
}
});
},
usersListMedias: function(callback) {
var self = this;
monster.request({
resource: 'voip.users.listMedia',
data: {
accountId: self.accountId
},
success: function(data) {
callback(data.data);
}
});
},
usersGetData: function(callback) {
var self = this;
monster.parallel({
users: function(callback) {
monster.request({
resource: 'voip.users.getUsers',
data: {
accountId: self.accountId
},
success: function(dataUsers) {
callback(null, dataUsers.data);
}
});
},
callflows: function(callback) {
self.usersListCallflows(function(callflows) {
callback(null, callflows);
});
},
devices: function(callback) {
monster.request({
resource: 'voip.users.listDevices',
data: {
accountId: self.accountId
},
success: function(dataDevices) {
callback(null, dataDevices.data);
}
});
}
},
function(err, results) {
callback && callback(results);
}
);
},
usersUpdateDevices: function(data, userId, callbackAfterUpdate) {
var self = this,
updateDevices = function(userCallflow) {
var listFnParallel = [];
_.each(data.new, function(deviceId) {
listFnParallel.push(function(callback) {
self.usersGetDevice(deviceId, function(data) {
data.owner_id = userId;
self.usersUpdateDevice(data, function(data) {
callback(null, data);
});
});
});
});
_.each(data.old, function(deviceId) {
listFnParallel.push(function(callback) {
self.usersGetDevice(deviceId, function(data) {
delete data.owner_id;
self.usersUpdateDevice(data, function(data) {
callback(null, data);
});
});
});
});
if(data.old.length > 0 && userCallflow && userCallflow.flow.module === 'ring_group') {
var endpointsCount = userCallflow.flow.data.endpoints.length;
userCallflow.flow.data.endpoints =_.filter(userCallflow.flow.data.endpoints, function(endpoint) {
return (data.old.indexOf(endpoint.id) < 0);
});
if(userCallflow.flow.data.endpoints.length < endpointsCount) {
if(userCallflow.flow.data.endpoints.length === 0) {
userCallflow.flow.module = 'user';
userCallflow.flow.data = {
can_call_self: false,
id: userId,
timeout: "20"
}
listFnParallel.push(function(callback) {
self.usersGetUser(userId, function(user) {
user.smartpbx.find_me_follow_me.enabled = false;
self.usersUpdateUser(user, function(data) {
callback(null, data)
});
});
});
}
listFnParallel.push(function(callback) {
self.usersUpdateCallflow(userCallflow, function(data) {
callback(null, data);
});
});
}
}
monster.parallel(listFnParallel, function(err, results) {
callbackAfterUpdate && callbackAfterUpdate(results);
});
};
self.usersListCallflowsUser(userId, function(data) {
if(data.length > 0) {
monster.request({
resource: 'voip.users.getCallflow',
data: {
accountId: self.accountId,
callflowId: data[0].id
},
success: function(callflow) {
updateDevices(callflow.data);
}
});
} else {
updateDevices(null);
}
});
},
usersUpdateCallflowNumbers: function(userId, callflowId, numbers, callback) {
var self = this;
if(numbers.length > 0) {
if(callflowId) {
monster.request({
resource: 'voip.users.getCallflow',
data: {
accountId: self.accountId,
callflowId: callflowId
},
success: function(getCallflowData) {
getCallflowData.data.numbers = numbers;
self.usersUpdateCallflow(getCallflowData.data, function(callflowData) {
callback && callback(callflowData);
});
}
});
}
else {
if(numbers[0].length < 7) {
self.usersMigrateFromExtensions(userId, numbers, function(data) {
callback && callback(data);
});
}
else {
toastr.error(self.i18n.active().users.needExtensionFirst);
}
}
}
else {
toastr.error(self.i18n.active().users.noNumberCallflow);
}
},
usersListNumbers: function(callback) {
var self = this;
monster.request({
resource: 'voip.users.getNumbers',
data: {
accountId: self.accountId
},
success: function(numbers) {
callback && callback(numbers.data);
}
});
},
usersUpdateCallflow: function(callflow, callback) {
var self = this;
monster.request({
resource: 'voip.users.updateCallflow',
data: {
accountId: self.accountId,
callflowId: callflow.id,
data: callflow
},
success: function(callflowData) {
callback && callback(callflowData.data);
}
});
},
usersCreateCallflow: function(callflow, callback) {
var self = this;
monster.request({
resource: 'voip.users.createCallflow',
data: {
accountId: self.accountId,
data: callflow
},
success: function(callflowData) {
callback && callback(callflowData.data);
}
});
},
/* If user has a vmbox, then only update it if it comes from the user form.
If the check comes from the extension page, where we create a callflow,
then only update the vmbox if there are no vmbox attached to this user */
usersSmartUpdateVMBox: function(user, needVMUpdate, callback) {
var self = this;
self.usersListVMBoxesUser(user.id, function(vmboxes) {
if(vmboxes.length > 0) {
if(needVMUpdate) {
self.usersGetVMBox(vmboxes[0].id, function(vmbox) {
vmbox = $.extend(true, {}, vmbox, user.extra.vmbox);
vmbox.name = user.first_name + ' ' + user.last_name + '\'s VMBox';
self.usersUpdateVMBox(vmbox, function(vmbox) {
callback && callback(vmbox);
});
});
}
else {
callback && callback(vmboxes[0]);
}
}
else {
var vmbox = {
owner_id: user.id,
mailbox: user.extra.vmbox.mailbox,
name: user.first_name + ' ' + user.last_name + '\'s VMBox',
timezone: user.timezone
};
self.usersCreateVMBox(vmbox, function(vmbox) {
callback && callback(vmbox);
});
}
});
},
usersUpdateConferencing: function(data, globalCallback) {
var self = this;
monster.parallel({
conference: function(callback) {
var baseConference = {
name: data.user.first_name + ' ' + data.user.last_name + ' SmartPBX Conference',
owner_id: data.user.id,
play_name_on_join: true,
member: {
numbers: []
}
};
baseConference = $.extend(true, {}, baseConference, data.conference);
self.usersListConferences(data.user.id, function(conferences) {
var conferenceToSave = baseConference;
if(conferences.length > 0) {
conferenceToSave = $.extend(true, {}, conferences[0], baseConference);
self.usersUpdateConference(conferenceToSave, function(conference) {
callback && callback(null, conference);
});
}
else {
self.usersCreateConference(conferenceToSave, function(conference) {
callback && callback(null, conference);
});
}
});
},
user: function(callback) {
if(data.user.smartpbx && data.user.smartpbx.conferencing && data.user.smartpbx.conferencing.enabled === true) {
callback && callback(null, data.user);
}
else {
data.user.smartpbx = data.user.smartpbx || {};
data.user.smartpbx.conferencing = data.user.smartpbx.conferencing || {};
data.user.smartpbx.conferencing.enabled = true;
self.usersUpdateUser(data.user, function(user) {
callback && callback(null, user);
});
}
}
},
function(err, results) {
globalCallback && globalCallback(results);
}
);
},
usersUpdateFaxing: function(data, faxboxData, globalCallback) {
var self = this;
monster.parallel({
callflow: function(callback) {
var baseCallflow = {};
self.usersListCallflowsUser(data.user.id, function(callflows) {
_.each(callflows, function(callflow) {
if(callflow.type === 'faxing') {
baseCallflow.id = callflow.id;
return false;
}
});
self.usersUpdateCallflowFaxing(data.user, faxboxData, baseCallflow, function(callflow) {
console.log(callflow);
callback && callback(null, callflow);
});
});
},
user: function(callback) {
if(data.user.smartpbx && data.user.smartpbx.faxing && data.user.smartpbx.faxing.enabled === true) {
callback && callback(null, data.user);
}
else {
data.user.smartpbx = data.user.smartpbx || {};
data.user.smartpbx.faxing = data.user.smartpbx.faxing || {};
data.user.smartpbx.faxing.enabled = true;
self.usersUpdateUser(data.user, function(user) {
callback && callback(null, user);
});
}
}
},
function(err, results) {
globalCallback && globalCallback(results);
}
);
},
usersUpdateCallflowFaxing: function(user, faxbox, callflow, callback) {
var self = this,
baseCallflow = {
type: 'faxing',
owner_id: faxbox.owner_id,
numbers: [ faxbox.caller_id ],
flow: {
module: 'faxbox',
children: {},
data: {
faxbox_id: faxbox.id
}
}
};
callflow = $.extend(true, {}, baseCallflow, callflow);
if(callflow.id) {
self.callApi({
resource: 'faxbox.update',
data:{
accountId: self.accountId,
faxboxId: faxbox.id,
data: faxbox
},
success: function(_data, status) {
self.usersUpdateCallflow(callflow, function(callflow) {
callback && callback(callflow);
});
},
error: function(_data, status) {
console.log(_data, status);
}
});
}
else {
var defaultFaxbox = {
name: user.first_name.concat(' ', user.last_name, self.i18n.active().users.faxing.defaultSettings.nameExtension),
caller_name: user.first_name.concat(' ', user.last_name),
fax_header: monster.config.company.name.concat(self.i18n.active().users.faxing.defaultSettings.headerExtension),
fax_identity: monster.util.formatPhoneNumber(faxbox.caller_id),
smtp_permission_list: [],
retries: 3,
fax_timezone: user.timezone,
notifications: {
inbound: {
email: {
send_to: user.email
}
},
outbound: {
email: {
send_to: user.email
}
}
}
};
faxbox = $.extend(true, {}, defaultFaxbox, faxbox);
self.callApi({
resource: 'faxbox.create',
data: {
accountId: self.accountId,
data: faxbox
},
success: function(_data, status) {
callflow.flow.data.faxbox_id = _data.data.id;
self.usersCreateCallflow(callflow, function(callflow) {
callback && callback(callflow);
});
}
});
}
},
usersDeleteConferencing: function(userId, globalCallback) {
var self = this;
monster.parallel({
conferences: function(callback) {
self.usersListConferences(userId, function(conferences) {
var listRequests = [];
_.each(conferences, function(conference) {
listRequests.push(function(subCallback) {
self.usersDeleteConference(conference.id, function(data) {
subCallback(null, data);
});
});
});
monster.parallel(listRequests, function(err, results) {
callback && callback(results);
});
});
},
user: function(callback) {
self.usersGetUser(userId, function(user) {
//user.conferencing_enabled = false;
user.smartpbx = user.smartpbx || {};
user.smartpbx.conferencing = user.smartpbx.conferencing || {};
user.smartpbx.conferencing.enabled = false;
self.usersUpdateUser(user, function(user) {
callback(null, user);
});
});
}
},
function(err, results) {
globalCallback && globalCallback(results);
}
);
},
usersDeleteFaxing: function(userId, globalCallback) {
var self = this;
monster.parallel({
callflows: function(callback) {
self.usersListCallflowsUser(userId, function(callflows) {
var listRequests = [];
_.each(callflows, function(callflow) {
if(callflow.type === 'faxing') {
listRequests.push(function(subCallback) {
self.callApi({
resource: 'callflow.get',
data: {
accountId: self.accountId,
callflowId: callflow.id
},
success: function(data, status) {
self.callApi({
resource: 'faxbox.delete',
data: {
accountId: self.accountId,
faxboxId: data.data.flow.data.faxbox_id
},
success: function(_data, status) {
self.usersDeleteCallflow(callflow.id, function(results) {
subCallback(null, results);
});
}
});
}
});
});
}
});
monster.parallel(listRequests, function(err, results) {
callback && callback(results);
});
});
},
user: function(callback) {
self.usersGetUser(userId, function(user) {
//user.faxing_enabled = false;
user.smartpbx = user.smartpbx || {};
user.smartpbx.faxing = user.smartpbx.faxing || {};
user.smartpbx.faxing.enabled = false;
self.usersUpdateUser(user, function(user) {
callback(null, user);
});
});
}
},
function(err, results) {
globalCallback && globalCallback(results);
}
);
},
usersSortExtensions: function(a, b) {
var parsedA = parseInt(a),
parsedB = parseInt(b),
result = -1;
if(parsedA > 0 && parsedB > 0) {
result = parsedA > parsedB;
}
return result;
},
usersRemoveOverlay: function() {
$('body').find('#users_container_overlay').remove();
}
};
return app;
});