diff --git a/src/api/call-forward.js b/src/api/call-forward.js index 19dd2e98..6eae6eb6 100644 --- a/src/api/call-forward.js +++ b/src/api/call-forward.js @@ -82,3 +82,96 @@ export function getDestinationsets(id) { }); }); } + +export function loadAlwaysEverybodyDestinations(subscriberId) { + return new Promise((resolve, reject)=>{ + Promise.resolve().then(()=>{ + return getMappings(subscriberId); + }).then((mappings)=>{ + let cfuPromises = []; + let cfnaPromises = []; + let cfbPromises = []; + if(_.has(mappings, 'cfu') && _.isArray(mappings.cfu) && mappings.cfu.length > 0) { + mappings.cfu.forEach((cfuMapping)=>{ + if (cfuMapping.timeset_id === null && cfuMapping.sourceset_id === null) { + cfuPromises.push(getDestinationsetById(cfuMapping.destinationset_id)); + } + }); + } + if(_.has(mappings, 'cfna') && _.isArray(mappings.cfna) && mappings.cfna.length > 0) { + mappings.cfna.forEach((cfnaMapping)=>{ + if (cfnaMapping.timeset_id === null && cfnaMapping.sourceset_id === null) { + cfnaPromises.push(getDestinationsetById(cfnaMapping.destinationset_id)); + } + }); + } + if(_.has(mappings, 'cfb') && _.isArray(mappings.cfb) && mappings.cfb.length > 0) { + mappings.cfb.forEach((cfbMapping)=>{ + if (cfbMapping.timeset_id === null && cfbMapping.sourceset_id === null) { + cfbPromises.push(getDestinationsetById(cfbMapping.destinationset_id)); + } + }); + } + return Promise.all([ + Promise.all(cfuPromises), + Promise.all(cfnaPromises), + Promise.all(cfbPromises) + ]); + }).then((res)=>{ + resolve({ + online: res[0], + offline: res[1], + busy: res[2] + }); + }).catch((err)=>{ + reject(err); + }); + }); +} + +export function getDestinationsetById(id) { + return new Promise((resolve, reject)=>{ + Vue.http.get('/api/cfdestinationsets/' + id).then((res)=>{ + let destinationset = getJsonBody(res.body); + delete destinationset['_links']; + resolve(destinationset); + }).catch((err)=>{ + reject(err); + }); + }); +} + +export function deleteDestinationFromDestinationset(options) { + let headers = { + 'Content-Type': 'application/json-patch+json' + }; + return new Promise((resolve, reject) => { + Vue.http.patch('/api/cfdestinationsets/' + options.id, [{ + op: 'replace', + path: '/destinations', + value: options.data + }], { headers: headers }).then(result => { + if (options.deleteDestinationset) { + deleteDestinationsetById(options.id).then((res) => { + resolve(res); + }).catch((err) => { + console.log(err); + }); + } else { + resolve(result); + }; + }).catch(err => { + reject(err); + }); + }); +} + +export function deleteDestinationsetById(id) { + return new Promise((resolve, reject) => { + Vue.http.delete('/api/cfdestinationsets/' + id).then(result => { + resolve(result); + }).catch(err => { + reject(err); + }); + }); +} diff --git a/src/components/pages/CallForward/AfterHours.vue b/src/components/pages/CallForward/AfterHours.vue index 2a25291a..6d46e694 100644 --- a/src/components/pages/CallForward/AfterHours.vue +++ b/src/components/pages/CallForward/AfterHours.vue @@ -1,5 +1,6 @@ - + + - diff --git a/src/components/pages/CallForward/CompanyHours.vue b/src/components/pages/CallForward/CompanyHours.vue index 9e344a7b..9418e281 100644 --- a/src/components/pages/CallForward/CompanyHours.vue +++ b/src/components/pages/CallForward/CompanyHours.vue @@ -1,5 +1,6 @@ - + + + + diff --git a/src/components/pages/CallForward/CscDestinations.vue b/src/components/pages/CallForward/CscDestinations.vue new file mode 100644 index 00000000..c4fdd107 --- /dev/null +++ b/src/components/pages/CallForward/CscDestinations.vue @@ -0,0 +1,55 @@ + + + + + {{ title }} + + + + + + + {{ $t('pages.callForward.forwardToNowhere') }} + + + + + + + + + + + + + + + diff --git a/src/filters/number-format.js b/src/filters/number-format.js index 3792bc06..eef12be7 100644 --- a/src/filters/number-format.js +++ b/src/filters/number-format.js @@ -1,12 +1,16 @@ - import url from 'url'; import { PhoneNumberUtil, PhoneNumberFormat } from 'google-libphonenumber'; +import { format } from 'quasar-framework' +const { capitalize } = format var phoneUtil = PhoneNumberUtil.getInstance(); export default function(number) { try { let phoneNumber = url.parse(number, true).auth.split(':')[0]; + if (isNaN(phoneNumber)) { + phoneNumber = normalizeDestination(url.parse(number, true)); + } return normalizeNumber(phoneNumber); } catch(err1) { return normalizeNumber(number); @@ -35,3 +39,15 @@ export function rawNumber(number) { } return ''; } + +export function normalizeDestination(destination) { + let normalizedDestination; + if (destination.host == 'app.local') { + normalizedDestination = destination.auth; + } else if (destination.host == 'voicebox.local') { + normalizedDestination = 'Voicemail'; + } else { + normalizedDestination = capitalize(destination.host.split('.')[0]); + } + return normalizedDestination; +} diff --git a/src/locales/en.json b/src/locales/en.json index 908dc788..568ad6a4 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -114,6 +114,26 @@ }, "timeUpdatedMsg": "Time updated!", "recurrenceUpdatedMsg": "Recurrence updated!" + }, + "callForward": { + "titles": { + "always": "Always", + "companyHours": "Company Hours", + "afterHours": "After Hours" + }, + "whenOnline": "When I am online ...", + "whenBusy": "When I am busy ...", + "whenOffline": "When I am offline ...", + "forwardTo": "forward to", + "firstRing": "first ring", + "thenRing": "then ring", + "for": "for", + "secs": "secs", + "forwardToNowhere": "forward to nowhere", + "removeDialogTitle": "Remove call forward destination", + "removeDialogText": "You are about to remove the destination {destination}", + "removeSuccessMessage": "Removed destination {destination}", + "removeErrorMessage": "An error occured while trying to delete the destination. Please try again." } }, "call": { diff --git a/src/store/call-forward.js b/src/store/call-forward.js index a77d7a60..6eaf8ef0 100644 --- a/src/store/call-forward.js +++ b/src/store/call-forward.js @@ -3,7 +3,9 @@ import _ from 'lodash'; import { getSourcesets, getDestinationsets, getTimesets, - getMappings } from '../api/call-forward'; + getMappings, loadAlwaysEverybodyDestinations, + deleteDestinationFromDestinationset, + deleteDestinationsetById } from '../api/call-forward'; export default { namespaced: true, @@ -11,7 +13,12 @@ export default { mappings: null, sourcesets: null, timesets: null, - destinationsets: null + destinationsets: null, + alwaysEverybodyDestinations: { + online: [], + busy: [], + offline: [] + } }, mutations: { loadMappings(state, result) { @@ -25,6 +32,9 @@ export default { }, loadDestinationsets(state, result) { state.destinationsets = result; + }, + loadAlwaysEverybodyDestinations(state, result) { + state.alwaysEverybodyDestinations = result; } }, actions: { @@ -53,7 +63,7 @@ export default { getTimesets(localStorage.getItem('subscriberId')) .then(result => { context.commit('loadTimesets', result); - }).catch(err => { + }).catch((err) => { reject(err); }); }); @@ -67,6 +77,33 @@ export default { reject(err); }); }); + }, + loadAlwaysEverybodyDestinations(context) { + return new Promise((resolve, reject)=>{ + loadAlwaysEverybodyDestinations(localStorage.getItem('subscriberId')).then((result)=>{ + context.commit('loadAlwaysEverybodyDestinations', result); + }) + }); + }, + deleteDestinationFromDestinationset(context, options) { + return new Promise((resolve, reject) => { + deleteDestinationFromDestinationset(options) + .then((result) => { + resolve(result); + }).catch((err) => { + reject(err); + }); + }); + }, + deleteDestinationsetById(context, id) { + return new Promise((resolve, reject) => { + deleteDestinationsetById(id) + .then((result) => { + resolve(result); + }).catch((err) => { + reject(err); + }); + }); } } }; diff --git a/t/api/call-forward.js b/t/api/call-forward.js index b52d0f8d..547c90e1 100644 --- a/t/api/call-forward.js +++ b/t/api/call-forward.js @@ -4,7 +4,8 @@ import Vue from 'vue'; import VueResource from 'vue-resource'; import { getMappings, getSourcesets, getTimesets, - getDestinationsets } from '../../src/api/call-forward'; + getDestinationsets, getDestinationsetById, + deleteDestinationFromDestinationset } from '../../src/api/call-forward'; import { assert } from 'chai'; Vue.use(VueResource); @@ -229,4 +230,133 @@ describe('CallForward', function(){ }); }); + it('should get all call forward destinationset by id', function(done){ + + let data = { + "_links": { + "collection": { + "href": "/api/cfdestinationsets/" + }, + "curies": { + "href": "http://purl.org/sipwise/ngcp-api/#rel-{rel}", + "name": "ngcp", + "templated": true + }, + "ngcp:subscribers": { + "href": "/api/subscribers/309" + }, + "profile": { + "href": "http://purl.org/sipwise/ngcp-api/" + }, + "self": { + "href": "/api/cfdestinationsets/3" + } + }, + "destinations": [ + { + "announcement_id": null, + "destination": "sip:3333@192.168.178.23", + "priority": 1, + "simple_destination": "3333", + "timeout": 60 + }, + { + "announcement_id": null, + "destination": "sip:3333@192.168.178.23", + "priority": 1, + "simple_destination": "3333", + "timeout": 90 + }, + { + "announcement_id": null, + "destination": "sip:vmu04ee2ae6-aa11-4cee-82fe-5ac57c11174e@voicebox.local", + "priority": 1, + "timeout": 300 + }, + { + "announcement_id": null, + "destination": "sip:04ee2ae6-aa11-4cee-82fe-5ac57c11174e@fax2mail.local", + "priority": 1, + "timeout": 300 + } + ], + "id": 3, + "name": "t2" + }; + + let responseData = { + "destinations": [ + { + "announcement_id": null, + "destination": "sip:3333@192.168.178.23", + "priority": 1, + "simple_destination": "3333", + "timeout": 60 + }, + { + "announcement_id": null, + "destination": "sip:3333@192.168.178.23", + "priority": 1, + "simple_destination": "3333", + "timeout": 90 + }, + { + "announcement_id": null, + "destination": "sip:vmu04ee2ae6-aa11-4cee-82fe-5ac57c11174e@voicebox.local", + "priority": 1, + "timeout": 300 + }, + { + "announcement_id": null, + "destination": "sip:04ee2ae6-aa11-4cee-82fe-5ac57c11174e@fax2mail.local", + "priority": 1, + "timeout": 300 + } + ], + "id": 3, + "name": "t2" + }; + + Vue.http.interceptors = []; + Vue.http.interceptors.unshift((request, next)=>{ + next(request.respondWith(JSON.stringify(data), { + status: 200 + })); + }); + getDestinationsetById('3').then((result)=>{ + assert.deepEqual(result, responseData); + done(); + }).catch((err)=>{ + done(err); + }); + }); + + it('should delete destination from call forward destinationset', function(done){ + + let options = { + id: 3, + data: { + "announcement_id": null, + "destination": "sip:3333@192.168.178.23", + "priority": 1, + "simple_destination": "3333", + "timeout": 60 + }, + deleteDestinationset: false + }; + + Vue.http.interceptors = []; + Vue.http.interceptors.unshift((request, next)=>{ + next(request.respondWith(JSON.stringify({}), { + status: 204 + })); + }); + deleteDestinationFromDestinationset(options).then((result)=>{ + assert.isOk(result); + done(); + }).catch((err)=>{ + done(err); + }); + }); + }); diff --git a/t/store/call-forward.js b/t/store/call-forward.js index e69de29b..514a0809 100644 --- a/t/store/call-forward.js +++ b/t/store/call-forward.js @@ -0,0 +1,40 @@ + +'use strict'; + +import CallForwardModule from '../../src/store/call-forward'; +import { assert } from 'chai'; + +describe('CallForward', function(){ + + it('should load always everybody destinations', function(){ + let state = { + alwaysEverybodyDestinations: [ + ] + }; + let data = { + busy: [], + offline: [{ + destinations: [{ + "announcement_id": null, + "destination": "sip:3333@192.168.178.23", + "priority": 1, + "simple_destination": "3333", + "timeout": 60 + }, + { + "announcement_id": null, + "destination": "sip:2222@192.168.178.23", + "priority": 1, + "simple_destination": "2222", + "timeout": 300 + }], + id: 3, + name: "csc_destinationset_1" + }], + online: [] + }; + CallForwardModule.mutations.loadAlwaysEverybodyDestinations(state, data); + assert.deepEqual(state.alwaysEverybodyDestinations, data); + }); + +});