cucm-axl
Version:
JavaScript library for Cisco CUCM AXL
332 lines (296 loc) • 10.9 kB
JavaScript
const axios = require('axios')
const parseXmlString = require('./parse-xml')
const js2xmlparser = require('js2xmlparser')
// capitalize the first letter of a string and return it
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
class Axl {
constructor(settings) {
this.host = settings.host
this.user = settings.user
this.pass = settings.pass
this.version = settings.version
this.js2xmlOptions = {
attributeString: '$',
declaration: {
include: false
}
}
}
/*** main AXL command runner ***/
async run (method, type, innerBody) {
const methodType = method + capitalizeFirstLetter(type)
const url = `https://${this.host}:8443/axl/`
const basicAuth = new Buffer(this.user + ':' + this.pass).toString('base64')
const headers = {
'Authorization': `Basic ${basicAuth}`,
'Content-Type': 'text/xml',
'SOAPAction': `CUCM:DB ver=${this.version} ${methodType}`
}
const body = `<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<axl:${methodType} xmlns:axl="http://www.cisco.com/AXL/API/${this.version}">
${innerBody}
</axl:${methodType}>
</soapenv:Body>
</soapenv:Envelope>`
try {
// console.log(`running cucm-axl request - ${method} ${type}`)
// POST request to CUCM
const res = await axios.post(url, body, {headers})
// parse XML to JSON
const json = await parseXmlString(res.data)
// extract and return relevant response data
let nsResponse
try {
// soapenv
nsResponse = json['soapenv:Envelope']['soapenv:Body'][`ns:${methodType}Response`]
} catch (e1) {
// soap
nsResponse = json['soap:Envelope']['soap:Body'][`ns2:${methodType}Response`]
}
// return nsResponse['return'][type] || nsResponse['return']
return nsResponse['return']['row'] || nsResponse['return'][type] || nsResponse['return']
} catch (e2) {
let errorMessage
try {
// try to parse the xml error
const json = await parseXmlString(e.response.data)
try {
// soapenv
errorMessage = json['soapenv:Envelope']['soapenv:Body']['soapenv:Fault']['faultstring']
} catch (e3) {
// soap
errorMessage = json['soap:Envelope']['soap:Body']['soap:Fault']['faultstring']
}
} catch (e4) {
// throw the whole original error message
throw e2
}
// throw parsed error message
throw errorMessage
}
}
/*** functions to add items ***/
addLine (details) {
// add all specified details
const innerBody = js2xmlparser.parse('line', details, this.js2xmlOptions)
// run command
return this.run('add', 'line', innerBody)
}
addPhone (details) {
// add all specified phone details
const innerBody = js2xmlparser.parse('phone', details, this.js2xmlOptions)
// run command
return this.run('add', 'phone', innerBody)
}
addRemoteDestination (details) {
// add all specified phone details
const innerBody = js2xmlparser.parse('remoteDestination', details, this.js2xmlOptions)
// run command
return this.run('add', 'remoteDestination', innerBody)
}
/*** functions to get items ***/
getLine (searchCriteria) {
// iterate over searchCriteria and add each to the inner body
let innerBody = ''
for (let key in searchCriteria) {
innerBody += `<${key}>${searchCriteria[key]}</${key}>`
}
// run command
return this.run('get', 'line', innerBody)
}
getPhone (searchCriteria) {
// iterate over searchCriteria and add each to the inner body
let innerBody = ''
for (let key in searchCriteria) {
innerBody += `<${key}>${searchCriteria[key]}</${key}>`
}
// const innerBody = js2xmlparser.parse('phone', details, this.js2xmlOptions)
// run command
return this.run('get', 'phone', innerBody)
}
getRemoteDestination (searchCriteria) {
// create XML
// const innerBody = js2xmlparser.parse('phone', details, this.js2xmlOptions)
let innerBody = ''
for (let key in searchCriteria) {
innerBody += `<${key}>${searchCriteria[key]}</${key}>`
}
// run command
return this.run('get', 'remoteDestination', innerBody)
}
/*** functions to list items ***/
listLines (searchCriteria, returnedTags) {
// add all specified search criteria
let innerBody = '<searchCriteria>'
for (let key in searchCriteria) {
innerBody += `<${key}>${searchCriteria[key]}</${key}>`
}
innerBody += '</searchCriteria>'
// add all specified returnedTags
innerBody += '<returnedTags>'
for (let key in returnedTags) {
innerBody += `<${returnedTags[key]}/>`
}
innerBody += '</returnedTags>'
// run command
return this.run('list', 'line', innerBody)
}
listPhones (searchCriteria, returnedTags) {
// add all specified search criteria
let innerBody = '<searchCriteria>'
for (let key in searchCriteria) {
innerBody += `<${key}>${searchCriteria[key]}</${key}>`
}
innerBody += '</searchCriteria>'
// add all specified returnedTags
innerBody += '<returnedTags>'
for (let key in returnedTags) {
innerBody += `<${returnedTags[key]}/>`
}
innerBody += '</returnedTags>'
// run command
return this.run('list', 'phone', innerBody)
}
/*** functions to remove items ***/
removeLine (details) {
// add all specified phone details
let innerBody = ''
for (let key in details) {
innerBody += `<${key}>${details[key]}</${key}>`
}
// run command
return this.run('remove', 'line', innerBody)
}
removePhone (details) {
// add all specified phone details
let innerBody = ''
for (let key in details) {
innerBody += `<${key}>${details[key]}</${key}>`
}
// run command
return this.run('remove', 'phone', innerBody)
}
removeRemoteDestination (details) {
// add all specified phone details
let innerBody = ''
for (let key in details) {
innerBody += `<${key}>${details[key]}</${key}>`
}
// run command
return this.run('remove', 'remoteDestination', innerBody)
}
getApplicationUserDeviceAssociations (name) {
let query = `SELECT * FROM applicationuserdevicemap
WHERE fkapplicationuser = (SELECT pkid from applicationuser WHERE name = '${name}')`
return this.sqlQuery(query)
}
getApplicationUserUuid (name) {
let query = `SELECT pkid from applicationuser WHERE name = '${name}'`
return this.sqlQuery(query)
}
/*** other functions ***/
associateDeviceWithApplicationUser (deviceUuid, appUserName) {
let query = `INSERT INTO applicationuserdevicemap (fkapplicationuser, fkdevice, tkuserassociation) VALUES ( (SELECT pkid from applicationuser WHERE name = '${appUserName}'), '${deviceUuid}', 1)`
return this.sqlUpdate(query)
}
associateDeviceWithEndUser (deviceUuid, username) {
let query = `INSERT INTO enduserdevicemap (fkenduser, fkdevice, tkuserassociation) VALUES ( (SELECT pkid from enduser WHERE userid = '${username}'), '${deviceUuid}', 1)`
return this.sqlUpdate(query)
}
getEndUserIpccExtension (username) {
let query = `SELECT numplan.dnorpattern, numplan.description, routepartition.name as routepartition FROM numplan
JOIN endusernumplanmap ON (endusernumplanmap.fknumplan = numplan.pkid)
JOIN routepartition ON (routepartition.pkid = numplan.fkroutepartition)
WHERE fkenduser = (SELECT pkid FROM enduser WHERE userid = '${username}')
AND tkdnusage = '2'`
return this.sqlQuery(query)
}
// @deprecated
setEndUserIpccExtension (username, extension, routePartition) {
return insertEndUserIpccExtension(username, extension, routePartition)
}
insertEndUserIpccExtension (username, extension, routePartition) {
let query = `INSERT INTO endusernumplanmap (fkenduser, fknumplan, tkdnusage)
VALUES (
(SELECT pkid FROM enduser WHERE userid = '${username}'),
(SELECT numplan.pkid FROM numplan
JOIN routepartition ON (routepartition.pkid = numplan.fkroutepartition)
WHERE numplan.dnorpattern = '${extension}'
AND routepartition.name = '${routePartition}'),
'2'
)`
return this.sqlUpdate(query)
}
deleteEndUserIpccExtension (username, extension, routePartition) {
let query = `DELETE FROM endusernumplanmap
WHERE fkenduser = (SELECT pkid FROM enduser WHERE userid = '${username}')
AND fknumplan = (SELECT numplan.pkid FROM numplan
JOIN routepartition ON (routepartition.pkid = numplan.fkroutepartition)
WHERE numplan.dnorpattern = '${extension}'
AND routepartition.name = '${routePartition}')
AND tkdnusage = '2'`
return this.sqlUpdate(query)
}
listDevicesAndDns (pattern) {
let query = `SELECT d.name, d.description, t.name model, n.dnorpattern dialed_number, n.tkautoanswer auto_answer
FROM numplan n
JOIN devicenumplanmap map ON map.fknumplan = n.pkid
JOIN device d ON map.fkdevice = d.pkid
JOIN typemodel t ON d.tkmodel = t.enum
WHERE dnorpattern LIKE '${pattern}'`
return this.sqlQuery(query)
}
sqlQuery (query) {
let innerBody = `<sql>${query}</sql>`
return this.run('execute', 'SQLQuery', innerBody)
}
sqlUpdate (query) {
let innerBody = `<sql>${query}</sql>`
return this.run('execute', 'SQLUpdate', innerBody)
}
// initiate a sync of the CUCM LDAP directory using name provided in parameter
doLdapSync (name) {
// build inner body
const innerBody = `<name>${name}</name> <sync>true</sync>`
// run command
return this.run('do', 'ldapSync', innerBody)
}
// get status of CUCM LDAP directory sync using name provided in parameter
getLdapSyncStatus (name) {
// build inner body
const innerBody = `<name>${name}</name>`
// run command
return this.run('get', 'ldapSyncStatus', innerBody)
}
// update end user
updateUser (userId, ipccExtension) {
// build inner body
const innerBody = `<userid>${userId}</userid>
<ipccExtension>${ipccExtension}<ipccExtension>`
// run command
return this.run('update', 'user', innerBody)
}
// get end user
getUser (searchCriteria) {
let innerBody = ''
for (let key in searchCriteria) {
innerBody += `<${key}>${searchCriteria[key]}</${key}>`
}
// run command
return this.run('get', 'user', innerBody)
}
// add end user
addUser (details) {
// add all specified details
const innerBody = js2xmlparser.parse('user', details, this.js2xmlOptions)
// run command
return this.run('add', 'user', innerBody)
}
}
module.exports = Axl