cisco-axl 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Cisco AXL SOAP Library
2
2
 
3
- Simple library to pull AXL data Cisco CUCM via SOAP. The goal of this project is to make it easier for people to use AXL and to include all functionality of AXL!
3
+ A Javascript library to pull AXL data Cisco CUCM via SOAP. The goal of this project is to make it easier for people to use AXL and to include all functionality of AXL. This library utilizes [strong-soap](https://www.npmjs.com/package/strong-soap) to read Cisco's WSDL file. As a result this library can use any function in the schema for the version that you specify.
4
4
 
5
5
  Administrative XML (AXL) information can be found at:
6
6
  [Administrative XML (AXL) Reference](https://developer.cisco.com/docs/axl/#!axl-developer-guide).
@@ -30,10 +30,10 @@ NODE_TLS_REJECT_UNAUTHORIZED=0
30
30
 
31
31
  ## Features
32
32
 
33
- * This library uses strong-soap to parse the AXL WSDL file. As a result any AXL function for your specified version is avaliable to use!
34
- * Supports the Promise API
35
- * Returns all results in JSON rather than XML
36
- * Automatically cleans up SQL queries to avoid injection
33
+ - This library uses strong-soap to parse the AXL WSDL file. As a result any AXL function for your specified version is avaliable to use!
34
+ - Supports the Promise API. Can chain procedures together or you could use Promise.all() to run multiple "get" operations at the same time.
35
+ - Returns all results in JSON rather than XML. Function has options to remove all blank or empty fields from JSON results via optional clean parameter.
36
+ - Support for [json-variables](https://codsen.com/os/json-variables). The executeOperation function will recognize the dataContainerIdentifierTails from json-variables and remove them from your call. This avoids any SOAP fault issues from having extra information in call. See examples folder for use case.
37
37
 
38
38
  ## Usage
39
39
 
@@ -42,37 +42,154 @@ const axlService = require("cisco-axl");
42
42
 
43
43
  let service = new axlService("10.10.20.1", "administrator", "ciscopsdt");
44
44
 
45
- var method = "addRoutePartition";
46
- var params = {
45
+ var operation = "addRoutePartition";
46
+ var tags = {
47
47
  routePartition: {
48
- name: 'INTERNAL-PT',
49
- description: 'Internal directory numbers',
50
- timeScheduleIdName: '',
51
- useOriginatingDeviceTimeZone: '',
52
- timeZone: '',
53
- partitionUsage: ''
54
- }
48
+ name: "INTERNAL-PT",
49
+ description: "Internal directory numbers",
50
+ timeScheduleIdName: "",
51
+ useOriginatingDeviceTimeZone: "",
52
+ timeZone: "",
53
+ partitionUsage: "",
54
+ },
55
55
  };
56
56
 
57
57
  service
58
- .executeMethod(method, params)
59
- .then((results) => {
60
- console.log(`Here are a list of all the partitions on our cluster:`);
61
- results.routePartition.map((str) => {
62
- console.log(str.name);
63
- });
64
- })
65
- .catch((error) => {
58
+ .executeOperation(operation, tags)
59
+ .then((results) => {
60
+ console.log("addRoutePartition UUID", results);
61
+ })
62
+ .catch((error) => {
66
63
  console.log(error);
67
- });
64
+ });
68
65
  ```
69
66
 
67
+ ## Methods
68
+
69
+ - new axlService(options: obj)
70
+ - axlService.returnOperations(filter?: string)
71
+ - axlService.getOperationTags(operation: string)
72
+ - axlService.executeOperation(operation: string,tags: obj, opts?: obj)
73
+
74
+ ### new axlService(options)
75
+
76
+ Service constructor for methods. Requires a JSON object consisting of hostname, username, password and version.
77
+
78
+ ```node
79
+ let service = new axlService("10.10.20.1", "administrator", "ciscopsdt", "14.0");
80
+ ```
81
+
82
+ ### axlService.returnOperations(filter?) ⇒ Returns promise
83
+
84
+ Method takes optional argument to filter results. No argument returns all operations. Returns results via Promise.
85
+
86
+ | Method | Argument | Type | Obligatory | Description |
87
+ | :--------------- | :------- | :----- | :--------- | :---------------------------------- |
88
+ | returnOperations | filter | string | No | Provide a string to filter results. |
89
+
90
+ ### axlService.getOperationTags(operation) ⇒ Returns promise
91
+
92
+ Method requires passing an AXL operation. Returns results via Promise.
93
+
94
+ | Method | Argument | Type | Obligatory | Description |
95
+ | :--------------- | :-------- | :----- | :--------- | :----------------------------------------------------------------------- |
96
+ | getOperationTags | operation | string | Yes | Provide the name of the AXL operation you wish to retrieve the tags for. |
97
+
98
+ ### axlService.executeOperation(operation,tags,opts?) ⇒ Returns promise
99
+
100
+ Method requires passing an AXL operation and JSON object of tags. Returns results via Promise.
101
+
102
+ Current options include:
103
+ | option | type | description |
104
+ | :--------------------------- | :------ | :---------------------------------------------------------------------------------- |
105
+ | clean | boolean | Default: **false**. Allows method to remove all tags that have no values from return data. |
106
+ | dataContainerIdentifierTails | string | Default: **'\_data'**. executeOperation will automatically remove any tag with the defined string. This is used with json-variables library. |
107
+
108
+ Example:
109
+
110
+ ```node
111
+ var opts = {
112
+ clean: true,
113
+ dataContainerIdentifierTails: "_data",
114
+ };
115
+ ```
116
+
117
+ | Method | Argument | Type | Obligatory | Description |
118
+ | :--------------- | :-------- | :----- | :--------- | :--------------------------------------------------------- |
119
+ | executeOperation | operation | string | Yes | Provide the name of the AXL operation you wish to execute. |
120
+ | executeOperation | tags | object | Yes | Provide a JSON object of the tags for your operation. |
121
+ | executeOperation | opts | object | No | Provide a JSON object of options for your operation. |
122
+
70
123
  ## Examples
71
124
 
72
- Check /test/tests.js for more examples.
125
+ Check **examples** folder for different ways to use this library. Each folder should have a **README** to explain about each example.
126
+
127
+ You can also run the **tests.js** against Cisco's DevNet sandbox so see how each various method works.
73
128
 
74
129
  ```javascript
75
130
  npm run test
76
131
  ```
77
132
 
78
- Note: Test are using Cisco's DevNet sandbox information. Find more information here: [Cisco DevNet](https://devnetsandbox.cisco.com/)
133
+ Note: Test are using Cisco's DevNet sandbox information. Find more information here: [Cisco DevNet](https://devnetsandbox.cisco.com/).
134
+
135
+ ## json-variables support
136
+
137
+ At a tactical level, json-variables program lets you take a plain object (JSON files contents) and add special markers in any value which you can then reference in a different path.
138
+
139
+ This library will recoginize json-variables **\*\_data** keys in the tags and delete before executing the operation.
140
+
141
+ Example:
142
+
143
+ ```node
144
+ var lineTemplate = {
145
+ pattern: "%%_extension_%%",
146
+ routePartitionName: "",
147
+ alertingName: "%%_firstName_%% %%_lastName_%%",
148
+ asciiAlertingName: "%%_firstName_%% %%_lastName_%%",
149
+ description: "%%_firstName_%% %%_lastName_%%",
150
+ _data: {
151
+ extension: "1001",
152
+ firstName: "Tom",
153
+ lastName: "Smith",
154
+ },
155
+ };
156
+
157
+ const lineTags = jVar(lineTemplate);
158
+
159
+ service
160
+ .executeOperation("updateLine", lineTags)
161
+ .then((results) => {
162
+ console.log(results);
163
+ })
164
+ .catch((error) => {
165
+ console.log(error);
166
+ });
167
+ ```
168
+
169
+ Note: If you need to change the variables key you can so via options in both the json-variables and with executeOperations.
170
+
171
+ Example:
172
+
173
+ ```node
174
+ ...
175
+ const lineTags = jVar(lineTemplate,{ dataContainerIdentifierTails: "_variables"});
176
+
177
+ service.executeOperation("updateLine", lineTags,{ dataContainerIdentifierTails: "_variables"})
178
+ ...
179
+ ```
180
+
181
+ ## Limitations
182
+
183
+ Currently there is an issue with strong-soap regarding returning nillable values for element tags. These values show if a particular tags is optional or not. Once resolved a method will be added to return tags nillable status (true or false).
184
+
185
+ ## TODO
186
+
187
+ - Add more promised based examples, particularly a Promise.All() example.
188
+ - Add example for reading in CSV and performing a bulk exercise with variables.
189
+ - Add example for saving SQL output to CSV or uploading to cloud (Airtable or SmartSheets).
190
+
191
+ ## Giving Back
192
+
193
+ If you would like to support my work and the time I put in creating the code, you can click the image below to get me a coffee. I would really appreciate it (but is not required).
194
+
195
+ [Buy Me a Coffee](https://www.buymeacoffee.com/automatebldrs)
@@ -0,0 +1,159 @@
1
+ const axlService = require("../../index");
2
+
3
+ /*
4
+ Ever wanted to change a phone model, but keep the existing one in CUCM? This script will attempt to migrate a phone to the new model.
5
+ It uses SQL queries to grab some of the product specific information for the new model.
6
+
7
+ We will be using axl to "getPhone" information and then make changes before calling the "addPhone" operation.
8
+ - First we will use the "getPhone" operation to return some values for the phone we will be using to copy.
9
+ - Next we will be using a number of SQL query's to validate settings needed for the new phone model
10
+ - Lastly we will be combining all this information so we can send them via AXL.
11
+
12
+ Note: axlService is Promised based, so we using a nested promise. We wait for the first promise to be fufilled before calling the nested one.
13
+ */
14
+
15
+ // Set up new AXL service
16
+ let service = new axlService(
17
+ "10.10.20.1",
18
+ "administrator",
19
+ "ciscopsdt",
20
+ "14.0"
21
+ );
22
+
23
+ (async () => {
24
+
25
+ // Variable needed for script
26
+
27
+ // What model are we going to convert our phone into?
28
+ // You can get a list of models in CUCM with the SQL query: 'SELECT name from typemodel'
29
+ var convertPhoneType = "Cisco 8865"; // Another example: Cisco Dual Mode for Android
30
+ var phoneNameCopyingFrom = "CSFUSER001";
31
+ var phoneNameCopyingTo = "SEP112233445566"; // Another example: BOTWORDENJ
32
+ var newPhoneDescription = "Test phone added via AXL";
33
+
34
+ // We're going to use the getPhone operation to retrieve the settings from the phone we want to copy. First we'll get the JSON arguments needed for our AXL call.
35
+ var operation = "getPhone";
36
+ var tags = await service.getOperationTags(operation);
37
+ // Print out our operation tags
38
+ console.log(tags);
39
+ // Update the name of phone that we want to copy
40
+ tags.name = phoneNameCopyingFrom;
41
+
42
+ // Execute the AXL call. We set the true flag to clean the output (removes any blank or undefined settings)
43
+ var returnPhoneTags = await service.executeOperation(operation, tags, true);
44
+
45
+ // Now we're going to add a new phone based on the settings. We will updating a few new settings based on the model we will be converting to.
46
+ operation = "addPhone";
47
+ returnPhoneTags.phone.name = phoneNameCopyingTo; // New phone name that we will be using
48
+ returnPhoneTags.phone.description = newPhoneDescription; // Add a description
49
+ returnPhoneTags.phone.product = convertPhoneType; // Model product and type
50
+ returnPhoneTags.phone.model = convertPhoneType;
51
+
52
+ // Next we'll be pulling some of the supported tags for our new phone type.
53
+ // This may not be all the settings you have to change when converting to a new model, but are the most common that I've run into.
54
+
55
+ // Phone button templates are device and protocol specific.
56
+ // Let's get a list of the templates configured on our cluster that we can use.
57
+
58
+ var phoneTemplateSQL = `SELECT model.name AS device, pt.name AS template, p.buttonnum, tf.name AS feature, dp.name AS protocol
59
+ FROM phonetemplate AS pt, phonebutton AS p, typemodel AS model, typefeature AS tf, typedeviceprotocol AS dp
60
+ WHERE pt.pkid = p.fkphonetemplate AND pt.tkmodel = model.enum AND pt.tkdeviceprotocol = dp.enum AND p.tkfeature = tf.enum
61
+ AND model.name='${convertPhoneType}'`;
62
+
63
+ operation = "executeSQLQuery";
64
+ tags = await service.getOperationTags(operation);
65
+ tags.sql = phoneTemplateSQL;
66
+ var phoneTemplate = await service.executeOperation(operation, tags);
67
+
68
+ // This is for SIP phones.
69
+ // Let's get a list of Security Profiles configured on our cluster that we can use.
70
+
71
+ var securityProfileNameSQL = `SELECT model.name AS device, sp.name AS PROFILE
72
+ FROM securityprofile sp
73
+ LEFT OUTER JOIN typemodel AS model ON sp.tkmodel = model.enum
74
+ WHERE (sp.tksecuritypolicy = 4 OR sp.tksecuritypolicy = 99) AND model.name = '${convertPhoneType}'
75
+ ORDER BY model.name`;
76
+
77
+ operation = "executeSQLQuery";
78
+ tags = await service.getOperationTags(operation);
79
+ tags.sql = securityProfileNameSQL;
80
+ var securityProfileName = await service.executeOperation(operation, tags);
81
+
82
+ // DND Option can only be set to non-Zero on devices that support the DND feature (in
83
+ // ProductSupportsFeature table). For those devices that support the feature, only the Ringer Off (0) is
84
+ // valid, unless a parameter is present in the PSF record. If a parameter value of 1 exists in PSF table, only
85
+ // Call Reject is valid. If the param value is (2), all options including Use Common Profile (2) are valid.
86
+ // Dual mode and remote destination profile only support the Call Reject option.
87
+
88
+ var dndOptionSQL = `select model.name,dp.name as protocol,p.param from typemodel as model,
89
+ typedeviceprotocol as dp,ProductSupportsFeature as p where p.tkmodel=model.enum and p.
90
+ tkSupportsFeature=(select enum from typesupportsfeature where name='Do Not Disturb')
91
+ and p.tkdeviceprotocol=dp.enum and model.tkclass=(select enum from typeclass where name=
92
+ 'Phone')and model.name='${convertPhoneType}' order by model.name`;
93
+
94
+ operation = "executeSQLQuery";
95
+ tags = await service.getOperationTags(operation);
96
+ tags.sql = dndOptionSQL;
97
+ var dndOption = await service.executeOperation(operation, tags);
98
+
99
+ // Maximum Number of Calls and Busy Trigger (Less than or equal to Max. Calls) values depend on model type.
100
+ // We'll use an SQL query to figure out what values we need for our model type.
101
+ // 200:4:2 (Max calls per device:default max calls per line:default busy trigger).
102
+
103
+ var maxBusySQL = `SELECT NAME,param
104
+ FROM typemodel AS model, productsupportsfeature AS p
105
+ WHERE p.tkmodel = model.enum
106
+ AND p.tksupportsfeature = (SELECT enum FROM typesupportsfeature WHERE NAME = 'Multiple Call Display')
107
+ AND model.tkclass = (SELECT enum FROM typeclass WHERE NAME = 'Phone') AND name='${convertPhoneType}'`;
108
+
109
+ operation = "executeSQLQuery";
110
+ tags = await service.getOperationTags(operation);
111
+ tags.sql = maxBusySQL;
112
+ var maxBusy = await service.executeOperation(operation, tags);
113
+
114
+ // Let's update our JSON with the necessary values from above. Note some will return multiple values. You may need to loop thru and find the one you want.
115
+
116
+ returnPhoneTags.phone.phoneTemplateName.value = phoneTemplate.row[0].template;
117
+ returnPhoneTags.phone.securityProfileName.value = securityProfileName.row[0].profile;
118
+
119
+ // Does this phone support DND? If so does it have a param value of 1
120
+ if(dndOption){
121
+ if(dndOption.row[0].param === '1'){
122
+ returnPhoneTags.phone.dndOption = "Call Reject";
123
+ }else{
124
+ returnPhoneTags.phone.dndOption = "Ringer Off";
125
+ }
126
+ }else{
127
+ delete returnPhoneTags.phone.dndOption;
128
+ }
129
+
130
+ // Let's split up our values we got back from CUCM. We'll be setting each line to the default for Max Number of Calls and minus one for our Busy Trigger.
131
+ var maxBusyArr = maxBusy.row[0].param.split(':');
132
+
133
+ // Loop thru all lines configured and update as needed.
134
+
135
+ returnPhoneTags.phone.lines.line.map((object) => {
136
+ object.maxNumCalls = maxBusyArr[2];
137
+ object.busyTrigger = maxBusyArr[2] - 1;
138
+ });
139
+
140
+ // Confidential Access Mode is returned from CUCM via AXL as undefined if not set on the phone we are copying.
141
+ // We either need to set it to '' or delete it complete. Since we're not using this feature, let's delete it from our JSON.
142
+
143
+ delete returnPhoneTags.phone.confidentialAccess;
144
+
145
+ // Print out updated JSON before we execute addPhone on CUCM via AXL
146
+
147
+ console.log(returnPhoneTags);
148
+
149
+ // Let's add our new phone. If successful we should get back a UUID of our new phone.
150
+ operation = "addPhone";
151
+ await service
152
+ .executeOperation(operation, returnPhoneTags)
153
+ .then((results) => {
154
+ console.log("New UUID",results);
155
+ })
156
+ .catch((error) => {
157
+ console.log(error);
158
+ });
159
+ })();
@@ -0,0 +1,39 @@
1
+ const axlService = require("../../index");
2
+
3
+ /*
4
+ Example of how to copy a phone. This is similar to the Super Copy function in CUCM. Just an example of how to do it via AXL.
5
+
6
+ Note: axlService is Promised based, so we using a nested promise. We wait for the first promise to be fufilled before calling the nested one.
7
+ */
8
+
9
+ // Set up new AXL service
10
+ let service = new axlService(
11
+ "10.10.20.1",
12
+ "administrator",
13
+ "ciscopsdt",
14
+ "14.0"
15
+ );
16
+
17
+ (async () => {
18
+ var operation = "getPhone";
19
+ var tags = await service.getOperationTags(operation);
20
+ tags.name = "CSFUSER001";
21
+
22
+ var returnPhoneTags = await service.executeOperation(operation, tags, true);
23
+
24
+ operation = "addPhone";
25
+ returnPhoneTags.phone.name = "CSFWORDENJ";
26
+ returnPhoneTags.phone.description = "Test phone added via AXL";
27
+ // Confidential Access Mode is returned from CUCM via AXL as undefined if not set on the phone we are copying.
28
+ // We either need to set it to '' or delete it complete. Since we're not using this feature, let's delete it from our JSON.
29
+ delete returnPhoneTags.phone.confidentialAccess;
30
+
31
+ await service
32
+ .executeOperation(operation, returnPhoneTags)
33
+ .then((results) => {
34
+ console.log(results);
35
+ })
36
+ .catch((error) => {
37
+ console.log(error);
38
+ });
39
+ })();
@@ -0,0 +1,3 @@
1
+ # Copy SIP Trunk
2
+
3
+ Use **cisco-axl** to copy a SIP trunk. Cisco doesn't provide a way to super copy a SIP trunk and add a new one. This script will pull the values for an existing trunk and then allow you to make a few updates and reinsert the new trunk.
@@ -0,0 +1,54 @@
1
+ const axlService = require("../../index");
2
+
3
+ /*
4
+ Example of how to copy a SIP Trunk. Cisco doesn't have a Super Copy option for this, but we can do it via AXL.
5
+ The new SIP trunk will need to have a new IP address for the destination address.
6
+
7
+ Note: axlService is Promised based, so we using a nested promise. We wait for the first promise to be fufilled before calling the nested one.
8
+ */
9
+
10
+ // Set up new AXL service
11
+ let service = new axlService(
12
+ "10.10.20.1",
13
+ "administrator",
14
+ "ciscopsdt",
15
+ "14.0"
16
+ );
17
+
18
+ (async () => {
19
+ // First let's get the tags needed for finding a SIP Trunk
20
+ var operation = "getSipTrunk";
21
+ var tags = await service.getOperationTags(operation);
22
+
23
+ // Let's update the returned JSON with the name of the trunk we are trying to copy
24
+ tags.name = "SIPTrunktoCUP";
25
+
26
+ // Make a call to AXL to get the information for the trunk we are copying.
27
+ // Note: we will be sending the clean flag to executeOperation. This will remove any keys in our return json that is empty, undefined or null.
28
+ var options = {
29
+ clean: true
30
+ };
31
+
32
+ var returnTrunk = await service.executeOperation(operation, tags, options);
33
+
34
+ // Update the JSON with our new values
35
+ operation = "addSipTrunk";
36
+ returnTrunk.sipTrunk.name = "SIPTrunktoCUP2";
37
+ returnTrunk.sipTrunk.description = "NEW SIP Trunk";
38
+ returnTrunk.sipTrunk.destinations.destination[0].addressIpv4 = '10.10.20.18';
39
+ returnTrunk.sipTrunk.destinations.destination[0].port = '5060';
40
+
41
+ // Confidential Access Mode is returned from CUCM via AXL as undefined if not set on the phone we are copying.
42
+ // We either need to set it to '' or delete it complete. Since we're not using this feature, let's delete it from our JSON.
43
+ delete returnTrunk.sipTrunk.confidentialAccess;
44
+
45
+ await service
46
+ .executeOperation(operation, returnTrunk)
47
+ .then((results) => {
48
+ console.log("addSipTrunk UUID", results);
49
+ })
50
+ .catch((error) => {
51
+ console.log(error);
52
+ });
53
+ })();
54
+
@@ -0,0 +1,15 @@
1
+ const axlService = require("../index");
2
+
3
+ // Set up new AXL service
4
+ let service = new axlService(
5
+ "10.10.20.1",
6
+ "administrator",
7
+ "ciscopsdt",
8
+ "14.0"
9
+ );
10
+
11
+ (async () => {
12
+ var operation = "addSipTrunk";
13
+ var tags = await service.getOperationTags(operation);
14
+ console.log(tags);
15
+ })();
@@ -0,0 +1,7 @@
1
+ # SQL Queries
2
+
3
+ Use **cisco-axl** to save SQL queries and execute whenever needed. sqlQuery.js will read in an ".sql" file and run the query for you. Just export the results to a csv or use in another operation.
4
+
5
+ The **fs.readFileSync** package will allow a more readable format to be read in and still able executed with the **executeSQLQuery** operation. This makes it easy to store useful queries and script them to run.
6
+
7
+ I've included examples of some useful queries.
@@ -0,0 +1,14 @@
1
+ SELECT
2
+ LIMIT 10 dnorpattern,
3
+ cfhrdn,
4
+ cfhrintdn,
5
+ cfbdestination,
6
+ cfbintdestination,
7
+ cfnadestination,
8
+ cfnaintdestination,
9
+ cfurdestination,
10
+ cfurintdestination,
11
+ devicefailuredn,
12
+ pffdestination,
13
+ pffintdestination
14
+ FROM numplan
@@ -0,0 +1,7 @@
1
+ SELECT
2
+ LIMIT 10 dnorpattern,
3
+ calledpartytransformationmask,
4
+ callingpartytransformationmask,
5
+ callingpartyprefixdigits,
6
+ prefixdigitsout
7
+ FROM numplan
@@ -0,0 +1,14 @@
1
+ SELECT NAME,
2
+ param
3
+ FROM typemodel AS model,
4
+ productsupportsfeature AS p
5
+ WHERE p.tkmodel = model.enum
6
+ AND p.tksupportsfeature =
7
+ (SELECT enum
8
+ FROM typesupportsfeature
9
+ WHERE NAME = 'Multiple Call Display')
10
+ AND model.tkclass =
11
+ (SELECT enum
12
+ FROM typeclass
13
+ WHERE NAME = 'Phone')
14
+ AND name='Cisco Dual Mode for Android'
@@ -0,0 +1,39 @@
1
+ const axlService = require("../../index");
2
+ var fs = require('fs');
3
+ var path = require('path');
4
+
5
+ /*
6
+ Example of how to send SQL queries to CUCM via AXL. We can store our queries in ".sql" files, then we can read them in before executing.
7
+
8
+ Note: axlService is Promised based, so we using a nested promise. We wait for the first promise to be fufilled before calling the nested one.
9
+ */
10
+
11
+ // Set up new AXL service
12
+ let service = new axlService(
13
+ "10.10.20.1",
14
+ "administrator",
15
+ "ciscopsdt",
16
+ "14.0"
17
+ );
18
+
19
+ (async () => {
20
+ // First we'll get the params needed to call executeSQLQuery
21
+ var operation = "executeSQLQuery";
22
+ var tags = await service.getOperationTags(operation);
23
+ console.log(tags);
24
+
25
+ // Next we'll read in our SQL file and update tags with the query
26
+ let sql = fs.readFileSync(path.join(__dirname, 'mask.sql'), "utf8");
27
+ tags.sql = sql;
28
+ console.log(tags);
29
+
30
+ // Lastly let's execute the query on server
31
+ await service
32
+ .executeOperation(operation, tags)
33
+ .then((results) => {
34
+ console.log(results);
35
+ })
36
+ .catch((error) => {
37
+ console.log(error);
38
+ });
39
+ })();
@@ -0,0 +1,25 @@
1
+ SELECT np.dnorpattern AS NUMBER,
2
+ np.description AS DESCRIPTION,
3
+ cfd.cfavoicemailenabled AS CALL_FORWARD_ALL_VOICEMAIL_ENABLED,
4
+ cfd.cfadestination AS CALL_FORWARD_ALL_DESTINATION,
5
+ cfbvoicemailenabled AS BUSY_VOICEMAIL_ENABLED,
6
+ cfbdestination AS BUSY_EXTERNAL_DESTINTATION,
7
+ cfbintvoicemailenabled AS BUSY_INTERNAL_VOICEMAIL_ENABLED,
8
+ cfbintdestination AS BUSY_INTERNAL_DESTINATION,
9
+ cfnavoicemailenabled AS NOANSWER_VOICEMAIL_ENABLED,
10
+ cfnadestination AS NO_ANSWERD_ESTINATION,
11
+ cfnaintvoicemailenabled AS NO_ANSWER_INTERNAL_VOICEMAIL_ENABLED,
12
+ cfnaintdestination AS NO_ANSWER_INTERNAL_DESTINATION,
13
+ rpt.name AS PARTITION
14
+ FROM numplan np
15
+ INNER JOIN typepatternusage tpu
16
+ ON np.tkpatternusage = tpu.enum
17
+ LEFT OUTER JOIN callforwarddynamic AS cfd
18
+ ON cfd.fknumplan = np.pkid
19
+ LEFT OUTER JOIN devicenumplanmap dnmp
20
+ ON dnmp.fknumplan = np.pkid
21
+ LEFT OUTER JOIN routepartition rpt
22
+ ON rpt.pkid = np.fkroutepartition
23
+ WHERE tpu.NAME = 'Device'
24
+ AND dnmp.pkid IS NULL
25
+ ORDER BY dnorpattern ASC
@@ -0,0 +1,11 @@
1
+ # Templates
2
+
3
+ Using json-variables you can use JSON files as templates along with variables to automate AXL operations.
4
+
5
+ ## Update Phone and Line
6
+
7
+ Every wanted to change an exsiting phone from one user to another user? This script will help you do that as well as updating all the display, line text labels, etc for the new user.
8
+
9
+ ## Add Phone and Update Line
10
+
11
+ This script will add a new phone and line. Once finished it will go back and update the line. AXL doesn't allow setting alertingName, asciiAlertingName and description while adding a line via the addPhone operation. This would be similar to using BAT to add phones.
@@ -0,0 +1,49 @@
1
+ const { jVar } = require("json-variables");
2
+ const axlService = require("../../../index");
3
+
4
+ /*
5
+ This script using json-variables (https://codsen.com/os/json-variables) to add a new phone from a template.
6
+ The AXL "addPhone" operation will either add an existing line or add a new one.
7
+ We will be using the "updateLine" to follow behind and update a few of the fields that "addPhone" does not include.
8
+
9
+ Note: axlService is Promised based, so we using a nested promise. We wait for the "addPhone" promise to be fufilled before calling "updateLine".
10
+ */
11
+
12
+ // Set up new AXL service (DevNet sandbox credentials: https://devnetsandbox.cisco.com/)
13
+ let service = new axlService(
14
+ "10.10.20.1",
15
+ "administrator",
16
+ "ciscopsdt",
17
+ "14.0"
18
+ );
19
+
20
+ // Read in the JSON templates
21
+ var phoneTemplate = require("./phoneTemplate.json");
22
+ var lineTemplate = require("./lineTemplate.json");
23
+
24
+ (async () => {
25
+ // Use json-variables to update our values from the template values
26
+ const phoneArg = jVar(phoneTemplate);
27
+ const lineArg = jVar(lineTemplate);
28
+
29
+ // Call the first operation: "addPhone" with the jVar updated json
30
+ service
31
+ .executeOperation("addPhone", phoneArg)
32
+ .then((results) => {
33
+ // Print out the UUID for the successful "addPhone" call
34
+ console.log("addPhone UUID", results);
35
+ // Call the second operation: "update" with the jVar updated json
36
+ service
37
+ .executeOperation("updateLine", lineArg)
38
+ .then((results) => {
39
+ // Print out the UUID for the successful "updateLine" call
40
+ console.log("updateLine UUID", results);
41
+ })
42
+ .catch((error) => {
43
+ console.log(error);
44
+ });
45
+ })
46
+ .catch((error) => {
47
+ console.log(error);
48
+ });
49
+ })();
@@ -0,0 +1,12 @@
1
+ {
2
+ "pattern": "%%_extension_%%",
3
+ "routePartitionName": "",
4
+ "alertingName": "%%_firstName_%% %%_lastName_%%",
5
+ "asciiAlertingName": "%%_firstName_%% %%_lastName_%%",
6
+ "description": "%%_firstName_%% %%_lastName_%%",
7
+ "_data": {
8
+ "extension": "2001",
9
+ "firstName": "Tom",
10
+ "lastName": "Smith"
11
+ }
12
+ }
@@ -0,0 +1,151 @@
1
+ {
2
+ "phone":{
3
+ "name":"%%_deviceName_%%",
4
+ "description":"%%_lastName_%%, %%_firstName_%% Extension %%_extension_%%",
5
+ "product":"Cisco Unified Client Services Framework",
6
+ "model":"Cisco Unified Client Services Framework",
7
+ "class":"Phone",
8
+ "protocol":"SIP",
9
+ "protocolSide":"User",
10
+ "devicePoolName":{
11
+ "value":"Default"
12
+ },
13
+ "commonPhoneConfigName":{
14
+ "value":"Standard Common Phone Profile"
15
+ },
16
+ "networkLocation":"Use System Default",
17
+ "locationName":{
18
+ "value":"Hub_None"
19
+ },
20
+ "loadInformation":{
21
+ "attributes":{
22
+ "special":"false"
23
+ }
24
+ },
25
+ "versionStamp":"",
26
+ "traceFlag":"false",
27
+ "mlppIndicationStatus":"Off",
28
+ "preemption":"Disabled",
29
+ "useTrustedRelayPoint":"Default",
30
+ "retryVideoCallAsAudio":"true",
31
+ "securityProfileName":{
32
+ "value":"Cisco Unified Client Services Framework - UDP"
33
+ },
34
+ "sipProfileName":{
35
+ "value":"Standard SIP Profile"
36
+ },
37
+ "useDevicePoolCgpnTransformCss":"true",
38
+ "sendGeoLocation":"false",
39
+ "lines":{
40
+ "line":[
41
+ {
42
+ "index":"1",
43
+ "label":"%%_lastName_%% - %%_extension_%%",
44
+ "display":"%%_lastName_%%, %%_firstName_%%",
45
+ "dirn":{
46
+ "pattern":"%%_extension_%%"
47
+ },
48
+ "ringSetting":"Ring",
49
+ "consecutiveRingSetting":"Use System Default",
50
+ "mwlPolicy":"Use System Policy",
51
+ "displayAscii":"%%_lastName_%%, %%_firstName_%%",
52
+ "maxNumCalls":"3",
53
+ "busyTrigger":"2",
54
+ "callInfoDisplay":{
55
+ "callerName":"true",
56
+ "callerNumber":"false",
57
+ "redirectedNumber":"false",
58
+ "dialedNumber":"true"
59
+ },
60
+ "recordingFlag":"Call Recording Disabled",
61
+ "audibleMwi":"Default",
62
+ "partitionUsage":"General",
63
+ "associatedEndusers":{
64
+ "enduser":[
65
+ {
66
+ "userId":"%%_userid_%%"
67
+ }
68
+ ]
69
+ },
70
+ "missedCallLogging":"true",
71
+ "recordingMediaSource":"Gateway Preferred"
72
+ }
73
+ ]
74
+ },
75
+ "numberOfButtons":"1",
76
+ "phoneTemplateName":{
77
+ "value":"Standard Client Services Framework"
78
+ },
79
+ "ringSettingIdleBlfAudibleAlert":"Default",
80
+ "ringSettingBusyBlfAudibleAlert":"Default",
81
+ "enableExtensionMobility":"false",
82
+ "currentProfileName":{
83
+
84
+ },
85
+ "currentConfig":{
86
+ "phoneTemplateName":{
87
+ "value":"Standard Client Services Framework"
88
+ },
89
+ "mlppIndicationStatus":"Off",
90
+ "preemption":"Disabled",
91
+ "ignorePresentationIndicators":"false",
92
+ "singleButtonBarge":"Default",
93
+ "joinAcrossLines":"Off",
94
+ "callInfoPrivacyStatus":"Default",
95
+ "dndRingSetting":"Disable",
96
+ "dndOption":"Ringer Off",
97
+ "alwaysUsePrimeLine":"Default",
98
+ "alwaysUsePrimeLineForVoiceMessage":"Default",
99
+ "emccCallingSearchSpaceName":{
100
+
101
+ }
102
+ },
103
+ "singleButtonBarge":"Default",
104
+ "joinAcrossLines":"Off",
105
+ "builtInBridgeStatus":"Default",
106
+ "callInfoPrivacyStatus":"Default",
107
+ "hlogStatus":"On",
108
+ "ignorePresentationIndicators":"false",
109
+ "packetCaptureMode":"None",
110
+ "packetCaptureDuration":"0",
111
+ "allowCtiControlFlag":"true",
112
+ "presenceGroupName":{
113
+ "value":"Standard Presence group"
114
+ },
115
+ "unattendedPort":"false",
116
+ "requireDtmfReception":"false",
117
+ "rfc2833Disabled":"false",
118
+ "certificateOperation":"No Pending Operation",
119
+ "certificateStatus":"None",
120
+ "deviceMobilityMode":"Default",
121
+ "remoteDevice":"false",
122
+ "dndOption":"Ringer Off",
123
+ "dndRingSetting":"Disable",
124
+ "dndStatus":"false",
125
+ "isActive":"true",
126
+ "isDualMode":"true",
127
+ "phoneSuite":"Default",
128
+ "phoneServiceDisplay":"Default",
129
+ "isProtected":"false",
130
+ "mtpRequired":"false",
131
+ "mtpPreferedCodec":"711ulaw",
132
+ "outboundCallRollover":"No Rollover",
133
+ "hotlineDevice":"false",
134
+ "alwaysUsePrimeLine":"Default",
135
+ "alwaysUsePrimeLineForVoiceMessage":"Default",
136
+ "deviceTrustMode":"Not Trusted",
137
+ "AllowPresentationSharingUsingBfcp":"false",
138
+ "allowiXApplicableMedia":"false",
139
+ "useDevicePoolCgpnIngressDN":"true",
140
+ "enableCallRoutingToRdWhenNoneIsActive":"f",
141
+ "enableActivationID":"false",
142
+ "allowMraMode":"false"
143
+ },
144
+ "phone_data":{
145
+ "firstName":"Tom",
146
+ "lastName":"Smith",
147
+ "extension":"2001",
148
+ "userid":"user01",
149
+ "deviceName": "CSFSMITHT"
150
+ }
151
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "pattern": "%%_extension_%%",
3
+ "routePartitionName": "",
4
+ "alertingName": "%%_firstName_%% %%_lastName_%%",
5
+ "asciiAlertingName": "%%_firstName_%% %%_lastName_%%",
6
+ "description": "%%_firstName_%% %%_lastName_%%",
7
+ "_data": {
8
+ "extension": "",
9
+ "firstName": "",
10
+ "lastName": ""
11
+ }
12
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "name":"%%_deviceName_%%",
3
+ "description":"%%_lastName_%%, %%_firstName_%% Extension %%_extension_%%",
4
+ "ownerUserName": "%%_userid_%%",
5
+ "lines":{
6
+ "line":[
7
+ {
8
+ "index":"1",
9
+ "dirn":{
10
+ "pattern":"%%_extension_%%"
11
+ },
12
+ "label":"%%_lastName_%% - %%_extension_%%",
13
+ "display":"%%_lastName_%%, %%_firstName_%%",
14
+ "displayAscii":"%%_lastName_%%, %%_firstName_%%",
15
+ "associatedEndusers":{
16
+ "enduser":[
17
+ {
18
+ "userId":"%%_userid_%%"
19
+ }
20
+ ]
21
+ }
22
+ }]
23
+ },
24
+ "_data": {
25
+ "deviceName":"",
26
+ "extension": "",
27
+ "firstName": "",
28
+ "lastName": "",
29
+ "userid":""
30
+ }
31
+ }
@@ -0,0 +1,106 @@
1
+ const { jVar } = require("json-variables");
2
+ const axlService = require("../../../index");
3
+
4
+ /*
5
+ Every wanted to change an exsiting phone from one user to another user? This script will help you do that as well as updating all the display,
6
+ line text labels, etc for the new user.
7
+
8
+ This script using json-variables (https://codsen.com/os/json-variables) to update a phone from a template.
9
+
10
+ We will be updating a phone from an existing user to a new user. This is a common MACD change for help desks.
11
+ - First we will use the "getUser" operation to return some values for the user we will be using to replace the existing user.
12
+ - Next we will take those values and update some of templates values.
13
+ - Next we will use jVar to merge those values for us so we can send them via AXL.
14
+
15
+ Note: axlService is Promised based, so we using a nested promise. We wait for the first promise to be fufilled before calling the nested one.
16
+ */
17
+
18
+ // Set up new AXL service (DevNet sandbox credentials: https://devnetsandbox.cisco.com/)
19
+ let service = new axlService(
20
+ "10.10.20.1",
21
+ "administrator",
22
+ "ciscopsdt",
23
+ "14.0"
24
+ );
25
+
26
+ // Read in the JSON templates
27
+ var phoneTemplate = require("./phoneTemplate.json");
28
+ var lineTemplate = require("./lineTemplate.json");
29
+
30
+ // Set up the tags for our "getUser" call. We are interested in getting the first and last name to use in our template later.
31
+
32
+ var deviceToUpdate = {
33
+ deviceName: "CSFUSER005",
34
+ extension: "1005"
35
+ };
36
+
37
+ // User to update phone value to
38
+
39
+ var getUserJSON = {
40
+ userid: "user03",
41
+ returnedTags: {
42
+ firstName: "",
43
+ lastName: "",
44
+ },
45
+ };
46
+
47
+ (async () => {
48
+ // Call getUser operation and store in the userInfo variable
49
+ var userInfo = await service
50
+ .executeOperation("getUser", getUserJSON)
51
+ .catch((error) => {
52
+ console.log(error);
53
+ });
54
+
55
+ // Let's update our variable data with the information that we got back from our AXL call
56
+ phoneTemplate._data.firstName = userInfo.user.firstName;
57
+ phoneTemplate._data.lastName = userInfo.user.lastName;
58
+ phoneTemplate._data.userid = getUserJSON.userid;
59
+ phoneTemplate._data.deviceName = deviceToUpdate.deviceName;
60
+ phoneTemplate._data.extension = deviceToUpdate.extension;
61
+ lineTemplate._data.firstName = userInfo.user.firstName;
62
+ lineTemplate._data.lastName = userInfo.user.lastName;
63
+ lineTemplate._data.extension = deviceToUpdate.extension;
64
+
65
+ // Use json-variables to update our values from the template values
66
+ const phoneTags = jVar(phoneTemplate);
67
+ const lineTags = jVar(lineTemplate);
68
+
69
+ // Call the first operation: "updatePhone" with the jVar updated json
70
+ service
71
+ .executeOperation("updatePhone", phoneTags)
72
+ .then((results) => {
73
+ // Print out the UUID for the successful "updatePhone" call
74
+ console.log("updatePhone UUID", results);
75
+ // Call the second operation: "updateLine" with the jVar updated json
76
+ service
77
+ .executeOperation("updateLine", lineTags)
78
+ .then((results) => {
79
+ // Print out the UUID for the successful "updateLine" call
80
+ console.log("updateLine UUID", results);
81
+ // Lastly let's update our user with the controlled device and set the primary ex
82
+ var updateUserJSON = {
83
+ userid: getUserJSON.userid,
84
+ associatedDevices: {
85
+ device: [deviceToUpdate.deviceName],
86
+ },
87
+ primaryExtension: { pattern: deviceToUpdate.extension, routePartitionName: '' }
88
+ };
89
+ service
90
+ .executeOperation("updateUser", updateUserJSON)
91
+ .then((results) => {
92
+ // Print out the UUID for the successful "updateUser" call
93
+ console.log("updateUser UUID", results);
94
+ })
95
+ .catch((error) => {
96
+ console.log(error);
97
+ });
98
+ })
99
+ .catch((error) => {
100
+ console.log(error);
101
+ });
102
+ })
103
+ .catch((error) => {
104
+ console.log(error);
105
+ });
106
+ })();
package/index.js CHANGED
@@ -1,7 +1,9 @@
1
- var soap = require("strong-soap").soap;
2
- var XMLHandler = soap.XMLHandler;
3
- var xmlHandler = new XMLHandler();
4
- var WSDL = soap.WSDL;
1
+ const soap = require("strong-soap").soap;
2
+ const WSDL = soap.WSDL;
3
+ const wsdlOptions = {
4
+ attributesKey: "attributes",
5
+ valueKey: "value",
6
+ };
5
7
 
6
8
  /**
7
9
  * Cisco axlService Service
@@ -20,10 +22,10 @@ class axlService {
20
22
  version: version,
21
23
  };
22
24
  }
23
- returnMethods(filter) {
25
+ returnOperations(filter) {
24
26
  var options = this._OPTIONS;
25
27
  return new Promise((resolve, reject) => {
26
- soap.createClient(options.url, {}, function (err, client) {
28
+ soap.createClient(options.url, wsdlOptions, function (err, client) {
27
29
  client.setSecurity(
28
30
  new soap.BasicAuthSecurity(options.username, options.password)
29
31
  );
@@ -59,7 +61,7 @@ class axlService {
59
61
  });
60
62
  });
61
63
  }
62
- getMethodParams(method) {
64
+ getOperationTags(operation) {
63
65
  var options = this._OPTIONS;
64
66
  return new Promise((resolve, reject) => {
65
67
  WSDL.open(
@@ -69,10 +71,10 @@ class axlService {
69
71
  if (err) {
70
72
  reject(err);
71
73
  }
72
- var operation =
73
- wsdl.definitions.bindings.AXLAPIBinding.operations[method];
74
- var operName = operation.$name;
75
- var operationDesc = operation.describe(wsdl);
74
+ var operationDef =
75
+ wsdl.definitions.bindings.AXLAPIBinding.operations[operation];
76
+ var operName = operationDef.$name;
77
+ var operationDesc = operationDef.describe(wsdl);
76
78
  var envelopeBody = {};
77
79
  operationDesc.input.body.elements.map((object) => {
78
80
  var operMatch = new RegExp(object.qname.name, "i");
@@ -95,13 +97,17 @@ class axlService {
95
97
  );
96
98
  });
97
99
  }
98
- executeMethod(method, params) {
100
+ executeOperation(operation, tags, opts) {
99
101
  var options = this._OPTIONS;
100
- var cleanParams = Object.fromEntries(
101
- Object.entries(params).filter(([_, v]) => v != "")
102
- );
102
+
103
+ var clean = opts?.clean ? opts.clean : false;
104
+ var dataContainerIdentifierTails = opts?.dataContainerIdentifierTails ? opts.dataContainerIdentifierTails : '_data';
105
+
106
+ // Let's remove empty top level strings. Also filter out json-variables
107
+ Object.keys(tags).forEach((k) => (tags[k] == '' || k.includes(dataContainerIdentifierTails)) && delete tags[k]);
108
+
103
109
  return new Promise((resolve, reject) => {
104
- soap.createClient(options.url, {}, function (err, client) {
110
+ soap.createClient(options.url, wsdlOptions, function (err, client) {
105
111
  client.setSecurity(
106
112
  new soap.BasicAuthSecurity(options.username, options.password)
107
113
  );
@@ -111,22 +117,27 @@ class axlService {
111
117
  reject(err.root.Envelope.Body.Fault);
112
118
  });
113
119
 
114
- var axlFunc = client.AXLAPIService.AXLPort[method];
120
+ var axlFunc = client.AXLAPIService.AXLPort[operation];
115
121
 
116
122
  axlFunc(
117
- cleanParams,
123
+ tags,
118
124
  function (
119
125
  err,
120
126
  result,
121
- envelope,
122
- rawResponse,
123
- soapHeader,
124
- rawRequest
125
127
  ) {
126
128
  if (err) {
127
129
  reject(err);
128
130
  }
129
- resolve(result.return);
131
+ if (result?.hasOwnProperty("return")) {
132
+ var output = result.return;
133
+ if (clean) {
134
+ output = cleanObj(result.return);
135
+ }
136
+ resolve(output);
137
+
138
+ } else {
139
+ reject('No return results');
140
+ }
130
141
  }
131
142
  );
132
143
  });
@@ -154,4 +165,24 @@ const nestedObj = (object) => {
154
165
  }
155
166
  };
156
167
 
168
+ const cleanObj = (object) => {
169
+ Object.entries(object).forEach(([k, v]) => {
170
+ if (v && typeof v === "object") {
171
+ cleanObj(v);
172
+ }
173
+ if (
174
+ (v && typeof v === "object" && !Object.keys(v).length) ||
175
+ v === null ||
176
+ v === undefined
177
+ ) {
178
+ if (Array.isArray(object)) {
179
+ object.splice(k, 1);
180
+ } else {
181
+ delete object[k];
182
+ }
183
+ }
184
+ });
185
+ return object;
186
+ };
187
+
157
188
  module.exports = axlService;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cisco-axl",
3
- "version": "1.0.1",
4
- "description": "Package to make Cisco AXL easier",
3
+ "version": "1.1.1",
4
+ "description": "A library to make Cisco AXL a lot easier",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 NODE_TLS_REJECT_UNAUTHORIZED=0 node ./test/tests.js"
@@ -21,6 +21,7 @@
21
21
  "strong-soap": "^3.4.0"
22
22
  },
23
23
  "devDependencies": {
24
+ "json-variables": "^10.1.0",
24
25
  "node-emoji": "^1.11.0"
25
26
  }
26
27
  }
package/test/tests.js CHANGED
@@ -20,70 +20,76 @@ var computer = emoji.get("computer");
20
20
  var finished = emoji.get("raised_hand");
21
21
 
22
22
  (async () => {
23
- console.log(`${spy} Let's first get a list of all the methods.`);
24
- var methodArr = await service.returnMethods();
25
- console.log(computer,methodArr);
23
+ console.log(`${spy} Let's first get a list of all the operations.`);
24
+ var operationArr = await service.returnOperations();
25
+ console.log(computer, "Found", operationArr.length,"operations.");
26
+ const random = Math.floor(Math.random() * operationArr.length);
27
+ console.log(`${spy} Let's pick out out at random operation: '`,operationArr[random],"'");
26
28
  console.log(
27
- `${next} Now let's get a list of all the methods that include the word 'partition'.`
29
+ `${next} Now let's get a list of all the operations that include the word 'partition'.`
28
30
  );
29
- var methodFilterArr = await service.returnMethods("partition");
30
- console.log(computer,methodFilterArr);
31
+ var operationFilteredArr = await service.returnOperations("partition");
32
+ console.log(computer, operationFilteredArr);
31
33
 
32
34
  console.log(
33
- `${cat} Great. Let's add a new route partition via 'addRoutePartition'.`
35
+ `${cat} Great. Let's add a new route partition via 'addRoutePartition' operation.`
34
36
  );
35
37
 
36
- var method = "addRoutePartition";
38
+ var operation = "addRoutePartition";
37
39
 
38
40
  console.log(
39
- `${next} We'll need to get what params to pass to the SOAP client first.`
41
+ `${next} We'll need to get what tags to pass to the SOAP client first.`
40
42
  );
41
- var params = await service.getMethodParams(method);
42
- console.log(computer,params);
43
- console.log(`${sparkles} Awesome, let's update the name and description fields.`);
44
- params.routePartition.name = "INTERNAL-PT";
45
- params.routePartition.description = "Internal directory numbers";
46
- console.log(computer,params);
43
+ var tags = await service.getOperationTags(operation);
44
+ console.log(computer, tags);
45
+ console.log(
46
+ `${sparkles} Magnificent, let's update the name and description fields.`
47
+ );
48
+ tags.routePartition.name = "INTERNAL-PT";
49
+ tags.routePartition.description = "Internal directory numbers";
50
+ console.log(computer, tags);
47
51
  console.log(
48
52
  `${next} Now we will attempt to add the new partition. Function should return an UUID to represent the new partition.`
49
53
  );
50
54
  await service
51
- .executeMethod(method, params)
55
+ .executeOperation(operation, tags)
52
56
  .then(async (results) => {
53
- console.log(computer,results);
57
+ console.log(computer, results);
54
58
  console.log(
55
- `${cat} Great let's get a list of all the partitions on our cluster now. First we'll get the params needed for this call.`
59
+ `${cat} Awesome, let's get a list of all the partitions on our cluster now. First we'll get the tags needed for this call.`
56
60
  );
57
61
 
58
- method = "listRoutePartition";
59
- params = await service.getMethodParams(method);
60
- console.log(computer,params);
62
+ operation = "listRoutePartition";
63
+ tags = await service.getOperationTags(operation);
64
+ console.log(computer, tags);
61
65
 
62
66
  console.log(
63
67
  `${spy} We want to list all partitions, so we'll be searching for a wildcard (%%) in the name and description fields.`
64
68
  );
65
- params.searchCriteria.name = "%%";
66
- params.searchCriteria.description = "%%";
67
- console.log(computer,params);
69
+ tags.searchCriteria.name = "%%";
70
+ tags.searchCriteria.description = "%%";
71
+ console.log(computer, tags);
68
72
  console.log(
69
- `${sparkles} Great, now that we've updated our params, we'll send the AXL request via SOAP.`
73
+ `${sparkles} Astounding, now that we've updated our tags, we'll send the AXL request via SOAP.`
70
74
  );
71
75
 
72
76
  await service
73
- .executeMethod(method, params)
77
+ .executeOperation(operation, tags)
74
78
  .then((results) => {
75
- console.log(`${list} Here are a list of all the partitions on our cluster:`);
79
+ console.log(
80
+ `${list} Here are a list of all the partitions on our cluster:`
81
+ );
76
82
  results.routePartition.map((str) => {
77
83
  var outString = `${check} ${str.name}`;
78
84
  console.log(outString);
79
85
  });
80
86
  })
81
87
  .catch((error) => {
82
- console.log(skull,error);
88
+ console.log(skull, error);
83
89
  });
84
90
  })
85
91
  .catch((error) => {
86
- console.log(skull,"Adding a new partition failed", error);
92
+ console.log(skull, "Adding a new partition failed", error);
87
93
  });
88
- console.log(finished,"Test all finished. Thanks!");
94
+ console.log(finished, "Test all finished. Thanks!");
89
95
  })();
package/test/wsdl.js ADDED
@@ -0,0 +1,38 @@
1
+ var soap = require("strong-soap").soap;
2
+ var WSDL = soap.WSDL;
3
+
4
+ var method = "addPhone";
5
+
6
+ const wsdlOptions = {
7
+ attributesKey: 'attributes',
8
+ valueKey: 'value',
9
+ xmlKey: 'xml',
10
+ };
11
+
12
+ WSDL.open(`./schema/current/AXLAPI.wsdl`, wsdlOptions, function (err, wsdl) {
13
+ if (err) {
14
+ reject(err);
15
+ }
16
+
17
+ var operation = wsdl.definitions.bindings.AXLAPIBinding.operations[method];
18
+ var schemas = wsdl.definitions;
19
+ var schema = wsdl.definitions.schemas['http://www.cisco.com/AXL/API/14.0'];
20
+ var operName = operation.$name;
21
+ var part = wsdl.definitions.messages.AXLError.parts;
22
+ var complexType = schema.complexTypes[method];
23
+ var operationDesc = operation.describe(wsdl);
24
+ var requestElements = operationDesc.input.body.elements[0].elements;
25
+
26
+ operationDesc.input.body.elements.map((object) => {
27
+ var operMatch = new RegExp(object.qname.name, "i");
28
+ if (operName.match(operMatch)) {
29
+ nestedObj(object);
30
+ }
31
+ });
32
+ });
33
+
34
+ const nestedObj = (object) => {
35
+ object.elements.map((object) => {
36
+ console.log(object.qname.name);
37
+ });
38
+ };