@adobe/acc-js-sdk 1.1.2 → 1.1.3
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/.github/workflows/npm-publish.yml +1 -1
- package/CHANGELOG.md +11 -0
- package/README.md +115 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/samples/utils.js +3 -1
- package/src/client.js +69 -14
- package/src/soap.js +28 -8
- package/test/client.hasPackage.test.js +6 -6
- package/test/client.test.js +332 -3
- package/test/soap.test.js +36 -2
|
@@ -16,7 +16,7 @@ jobs:
|
|
|
16
16
|
node-version: 10.0.0
|
|
17
17
|
- name: Publish if version has been updated
|
|
18
18
|
#uses: pascalgn/npm-publish-action@06e0830ea83eea10ed4a62654eeaedafb8bf50fc
|
|
19
|
-
uses: mkiki/npm-publish-action@
|
|
19
|
+
uses: mkiki/npm-publish-action@52879298d00c0a02781e1f02c9e917e01cff1bc7
|
|
20
20
|
with: # All of theses inputs are optional
|
|
21
21
|
tag_name: "v%s"
|
|
22
22
|
tag_message: "v%s"
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ This is a node.js SDK for Campaign API. It exposes the Campaign API exactly like
|
|
|
5
5
|
|
|
6
6
|
# Changelog
|
|
7
7
|
|
|
8
|
+
## Version 1.1.3
|
|
9
|
+
_2022/05/30_
|
|
10
|
+
|
|
11
|
+
* Fix a bug in client.hasPackage which was returning an incorrect result when passed a single parameter (it would always return false). Fixed the corresponding unit test too.
|
|
12
|
+
* Fix a bug causing API calls having a input parameter of type "int" to fail. Usually the type is described as "long", but sometimes "int" is used instead, such as, for instance, in the nms:extAccount#UpdateMCSynchWkf method.
|
|
13
|
+
* When using XML representations and DOMDocument method parameter type, the SDK expects to be passed an actual DOM document. Now it supports being passed a DOM element too. This is a common case when using the nms:delivery#createFromModel API followed by a xtk:session#Write API call.
|
|
14
|
+
* Avoid the error 'Cannot transform entity to xml because no XML root name was given' by using SOAP method parameter name as the default for XML document root when no other root is available
|
|
15
|
+
* Document how to set the password of an external account
|
|
16
|
+
* By default, SDK will send additional HTTP headers to help troubleshooting and usage tracking
|
|
17
|
+
* Add the ability to pass extra HTTP headers to API calls, either globally (to all HTTP headers), or locally, i.e. for a specific method
|
|
18
|
+
|
|
8
19
|
## Version 1.1.2
|
|
9
20
|
_2022/03/22_
|
|
10
21
|
|
package/README.md
CHANGED
|
@@ -130,7 +130,9 @@ noStorage|false|De-activate using of local storage
|
|
|
130
130
|
storage|localStorage|Overrides the local storage for caches
|
|
131
131
|
refreshClient|undefined|Async callback to run when the session token is expired
|
|
132
132
|
charset|UTF-8|The charset encoding used for http requests. In version 1.1.1 and above, the default will be UTF-8. It's possible to override (including setting an empty character set) with this option.
|
|
133
|
-
|
|
133
|
+
extraHttpHeaders|[string]:string|An optional dictionary (key/value pairs) of extra HTTP headers to pass to all API calls.
|
|
134
|
+
clientApp|string|An optional string describing the name and version of the SDK client application. It will be passed to the server in the ACC-SDK-Client-App HTTP header
|
|
135
|
+
noSDKHeaders|boolean|Can be set to disable passing ACC-SDK-* HTTP headers to the server
|
|
134
136
|
```js
|
|
135
137
|
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
136
138
|
"https://myInstance.campaign.adobe.com",
|
|
@@ -576,6 +578,49 @@ const document = DomUtil.fromJSON(json, "BadgerFish");
|
|
|
576
578
|
const json = DomUtil.toJSON(documentOrElement, "BadgerFish");
|
|
577
579
|
```
|
|
578
580
|
|
|
581
|
+
## Passing XML parameters
|
|
582
|
+
Many Campaign APIs take arguments which are DOM documents or DOM elements. For example, the nms:delivery#DeployTriggerMessages first argument is a DOMElement which is supposed to be a `<where>` clause used as a condition to select Message Center deliveries to publish.
|
|
583
|
+
|
|
584
|
+
```xml
|
|
585
|
+
<method name="DeployTriggerMessages" static="true">
|
|
586
|
+
<parameters>
|
|
587
|
+
<param inout="in" name="deliveries" type="DOMElement"/>
|
|
588
|
+
<param inout="in" name="localPublish" type="boolean"/>
|
|
589
|
+
</parameters>
|
|
590
|
+
</method>
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
For example, one would want to use the following condition to republish a particular delivery
|
|
594
|
+
|
|
595
|
+
```js
|
|
596
|
+
await client.NLWS.nmsDelivery.DeployTriggerMessages({
|
|
597
|
+
condition: [ {
|
|
598
|
+
expr: "@internalName='DM23'"
|
|
599
|
+
}]
|
|
600
|
+
}, false);
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
The JSON object corresponds to the following XML
|
|
604
|
+
```xml
|
|
605
|
+
<where>
|
|
606
|
+
<condition expr="@internalName='DM23'"/>
|
|
607
|
+
</where>
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
Note that in XML, unlike JSON, the root element `<where>` is explicitely named "where". When converting JSON to XML, there is no way for the SDK to know which tag name to used for the root XML element. The SDK contains some code to set it for the most common situation, but will rely on the user to specify, when necessary, the name of the root elment. This can be done using the `xtkschema` (all case insensitive) attribute as follows:
|
|
611
|
+
```js
|
|
612
|
+
await client.NLWS.nmsDelivery.DeployTriggerMessages({
|
|
613
|
+
xtkschema: 'xtk:where',
|
|
614
|
+
condition: [ {
|
|
615
|
+
expr: "@internalName='DM23'"
|
|
616
|
+
}]
|
|
617
|
+
}, false);
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
When the `xtkschema` attribute is set, the part after the colon (i.e. "where" in this example) will be used as the root element, effectively generating the right XML.
|
|
621
|
+
|
|
622
|
+
In our example, the `DeployTriggerMessages` will work properly regardless of the XML root of its `deliveries` parameter, so it's not needed to actually set the `xtkschema` attribute, but it's a best practice to do so, because some APIs will actually depend on receiving the right tag name.
|
|
623
|
+
|
|
579
624
|
## Error Management
|
|
580
625
|
|
|
581
626
|
If an API call fails (SOAP fault or HTTP error), a `CampaignException` object is thrown. This object contains the following attributes
|
|
@@ -654,6 +699,64 @@ const password = cipher.decryptPassword(encryptedPassword);
|
|
|
654
699
|
|
|
655
700
|
> **warning** This function is deprecated in version 1.0.0 of the SDK because it may break as we deploy Vault.
|
|
656
701
|
|
|
702
|
+
In order to set the password of an external account, you can use the `encryptPassword` API as follow
|
|
703
|
+
|
|
704
|
+
```js
|
|
705
|
+
const password = await this._client.NLWS.xtkSession.encryptPassword('password');
|
|
706
|
+
const account = {
|
|
707
|
+
xtkschema: "nms:extAccount",
|
|
708
|
+
name: name,
|
|
709
|
+
account: 'admin',
|
|
710
|
+
server: server,
|
|
711
|
+
password: password,
|
|
712
|
+
};
|
|
713
|
+
await this._client.NLWS.xtkSession.Write(account);
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
## HTTP Headers
|
|
718
|
+
|
|
719
|
+
### Out-of-the-box headers
|
|
720
|
+
In version 1.1.3 and above, the SDK will pass additional HTTP headers automatically
|
|
721
|
+
|
|
722
|
+
Header | Description
|
|
723
|
+
-------|------------
|
|
724
|
+
SOAPAction| name of the schema and SOAP method (ex: xtk:query#ExecuteQuery)
|
|
725
|
+
ACC-SDK-Version| Version of the SDK making the scores
|
|
726
|
+
ACC-SDK-Auth| Authentification type and ACC user
|
|
727
|
+
ACC-SDK-Client-App| Name of the application calling the client SDK
|
|
728
|
+
ACC-SDK-Call-RetryCount| In case an API call is retried, indicates the number of retries
|
|
729
|
+
ACC-SDK-Call-Internal| Indicates that an API call is performed byt the SDK for its own purpose
|
|
730
|
+
|
|
731
|
+
The `ACC-SDK` headers can be removed using the connection parameter `noSDKHeaders`.
|
|
732
|
+
|
|
733
|
+
### Custom HTTP headers
|
|
734
|
+
In version 1.1.3 and above, it is possible to pass additional HTTP headers or override HTTP headers set by the SDK. This can be done globally (i.e. for all API calls), or locally, i.e. just for a particular call, or both.
|
|
735
|
+
|
|
736
|
+
Http headers are passed through an object whose keys represent the header name and values the corresponding header value. Nothing particular is done in term of case sensitivity, headers will be passed as passed.
|
|
737
|
+
|
|
738
|
+
To set global HTTP headers for all API calls of a client, pass an http headers array in the connection parameters
|
|
739
|
+
```js
|
|
740
|
+
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
741
|
+
"https://myInstance.campaign.adobe.com",
|
|
742
|
+
"admin", "admin",
|
|
743
|
+
{ extraHttpHeaders: {
|
|
744
|
+
"X-ACC-JS-SDK-LBSAFE": "1",
|
|
745
|
+
"X-ACC-WEBUI-VERSION: "1.2"
|
|
746
|
+
} });
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
Subsequent API calls will have the corresponding headers set.
|
|
750
|
+
|
|
751
|
+
To set more HTTP headers for a particular API call, use the "headers" method of the NLWS object.
|
|
752
|
+
|
|
753
|
+
```js
|
|
754
|
+
const query = client.NLWS
|
|
755
|
+
.headers({'X-Test': 'hello'})
|
|
756
|
+
.xtkQueryDef.create(queryDef);
|
|
757
|
+
await query.executeQuery();
|
|
758
|
+
```
|
|
759
|
+
|
|
657
760
|
|
|
658
761
|
|
|
659
762
|
# Samples
|
|
@@ -1144,6 +1247,17 @@ const folder = {
|
|
|
1144
1247
|
await NLWS.xtkSession.write(folder);
|
|
1145
1248
|
````
|
|
1146
1249
|
|
|
1250
|
+
Some objects, such as deliveries are created from templates. The `createFromModel` API is preferred in this case. Given a template name, and a patch object, it will return an object created from the template and the patch, applying all sort of business rules and default values. This object can be inserted using a writer.
|
|
1251
|
+
|
|
1252
|
+
In this example, an email delivery is created from the "mail" delivery template and it's label is set to "Hello".
|
|
1253
|
+
|
|
1254
|
+
Note the xtkschema attribute in the second parameter of the `createFromModel` API call which is needed for the SDK to perform the proper JSON to XML transformation.
|
|
1255
|
+
|
|
1256
|
+
```js
|
|
1257
|
+
const mail = await client.NLWS.nmsDelivery.createFromModel('mail', { xtkschema:'nms:delivery', label:'Hello'});
|
|
1258
|
+
await client.NLWS.xtkSession.write(mail);
|
|
1259
|
+
````
|
|
1260
|
+
|
|
1147
1261
|
# Workflow API
|
|
1148
1262
|
|
|
1149
1263
|
Start and stop wotkflows, passing either an id or workflow internal name
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/acc-js-sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@adobe/acc-js-sdk",
|
|
9
|
-
"version": "1.1.
|
|
9
|
+
"version": "1.1.3",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"axios": "^0.25.0",
|
package/package.json
CHANGED
package/samples/utils.js
CHANGED
|
@@ -47,7 +47,9 @@ async function run(main) {
|
|
|
47
47
|
*/
|
|
48
48
|
async function logon(callback) {
|
|
49
49
|
var main = async () => {
|
|
50
|
-
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(url, user, password
|
|
50
|
+
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(url, user, password, {
|
|
51
|
+
clientApp: 'acc-js-sdk sample'
|
|
52
|
+
});
|
|
51
53
|
const client = await sdk.init(connectionParameters);
|
|
52
54
|
const NLWS = client.NLWS;
|
|
53
55
|
|
package/src/client.js
CHANGED
|
@@ -105,16 +105,35 @@ const xtkObjectHandler = {
|
|
|
105
105
|
* @private
|
|
106
106
|
* @memberof Campaign
|
|
107
107
|
*/
|
|
108
|
-
const clientHandler = (representation) => {
|
|
108
|
+
const clientHandler = (representation, headers) => {
|
|
109
109
|
return {
|
|
110
110
|
get: function(client, namespace) {
|
|
111
|
+
|
|
111
112
|
// Force XML or JSON representation (NLWS.xml or NLWS.json)
|
|
112
|
-
if (namespace == "xml") return new Proxy(client, clientHandler("xml"));
|
|
113
|
-
if (namespace == "json") return new Proxy(client, clientHandler("SimpleJson"));
|
|
113
|
+
if (namespace == "xml") return new Proxy(client, clientHandler("xml", headers));
|
|
114
|
+
if (namespace == "json") return new Proxy(client, clientHandler("SimpleJson", headers));
|
|
115
|
+
|
|
116
|
+
// Override HTTP headers (NLWS.headers({...}))
|
|
117
|
+
// Unlike NLWS.xml or NLWS.json, NLWS.headers returns a function. This function takes key/value
|
|
118
|
+
// pairs of headers, and, when called, returns a proxy object which will remember the headers
|
|
119
|
+
// and be able to pass them to subsequent SOAP call context
|
|
120
|
+
if (namespace == "headers") return (methodHeaders) => {
|
|
121
|
+
// Build of copy of the http headers and append new headers in order to accomodate
|
|
122
|
+
// chained calls, such as NLWS.headers(...).headers(...)
|
|
123
|
+
const newHeaders = {};
|
|
124
|
+
if (headers) for (let h in headers) newHeaders[h] = headers[h];
|
|
125
|
+
if (methodHeaders) for (let h in methodHeaders) newHeaders[h] = methodHeaders[h];
|
|
126
|
+
return new Proxy(client, clientHandler(representation, newHeaders));
|
|
127
|
+
};
|
|
114
128
|
|
|
115
129
|
return new Proxy({ client:client, namespace:namespace}, {
|
|
116
130
|
get: function(callContext, methodName) {
|
|
117
131
|
callContext.representation = representation;
|
|
132
|
+
callContext.headers = callContext.headers || client._connectionParameters._options.extraHttpHeaders;
|
|
133
|
+
if (headers) {
|
|
134
|
+
for (let h in headers) callContext.headers[h] = headers[h];
|
|
135
|
+
}
|
|
136
|
+
|
|
118
137
|
if (methodName == ".") return callContext;
|
|
119
138
|
|
|
120
139
|
// get Schema id from namespace (find first upper case letter)
|
|
@@ -248,6 +267,9 @@ class Credentials {
|
|
|
248
267
|
* @property {Storage} storage - Overrides the storage interface (i.e. LocalStorage)
|
|
249
268
|
* @property {function} refreshClient - An async callback function with the SDK client as parameter, which will be called when the ACC session is expired
|
|
250
269
|
* @property {string} charset - The charset encoding used for http requests. Defaults to UTF-8 since SDK version 1.1.1
|
|
270
|
+
* @property {{ name:string, value:string}} extraHttpHeaders - optional key/value pair of HTTP header (will override any other headers)
|
|
271
|
+
* @property {string} clientApp - optional name/version of the application client of the SDK. This will be passed in HTTP headers for troubleshooting
|
|
272
|
+
* @property {boolean} noSDKHeaders - set to disable "ACC-SDK" HTTP headers
|
|
251
273
|
* @memberOf Campaign
|
|
252
274
|
*/
|
|
253
275
|
|
|
@@ -312,6 +334,12 @@ class ConnectionParameters {
|
|
|
312
334
|
this._options._storage = storage;
|
|
313
335
|
this._options.refreshClient = options.refreshClient;
|
|
314
336
|
this._options.charset = options.charset === undefined ? "UTF-8": options.charset;
|
|
337
|
+
this._options.extraHttpHeaders = {};
|
|
338
|
+
if (options.extraHttpHeaders) {
|
|
339
|
+
for (let h in options.extraHttpHeaders) this._options.extraHttpHeaders[h] = options.extraHttpHeaders[h];
|
|
340
|
+
}
|
|
341
|
+
this._options.clientApp = options.clientApp;
|
|
342
|
+
this._options.noSDKHeaders = !!options.noSDKHeaders;
|
|
315
343
|
}
|
|
316
344
|
|
|
317
345
|
/**
|
|
@@ -684,13 +712,15 @@ class Client {
|
|
|
684
712
|
* @private
|
|
685
713
|
* @param {string} urn is the API name space, usually the schema. For instance xtk:session
|
|
686
714
|
* @param {string} method is the method to call, for instance Logon
|
|
715
|
+
* @param {boolean} internal is a boolean indicating whether the SOAP call is performed by the SDK (internal = true) or on behalf of a user
|
|
687
716
|
* @return {SOAP.SoapMethodCall} a SoapMethodCall which have been initialized with security tokens... and to which the method
|
|
688
717
|
* parameters should be set
|
|
689
718
|
*/
|
|
690
|
-
_prepareSoapCall(urn, method, internal) {
|
|
719
|
+
_prepareSoapCall(urn, method, internal, extraHttpHeaders) {
|
|
691
720
|
const soapCall = new SoapMethodCall(this._transport, urn, method,
|
|
692
721
|
this._sessionToken, this._securityToken,
|
|
693
|
-
this._getUserAgentString(), this._connectionParameters._options.charset
|
|
722
|
+
this._getUserAgentString(), this._connectionParameters._options.charset,
|
|
723
|
+
extraHttpHeaders);
|
|
694
724
|
soapCall.internal = !!internal;
|
|
695
725
|
return soapCall;
|
|
696
726
|
}
|
|
@@ -704,6 +734,7 @@ class Client {
|
|
|
704
734
|
*/
|
|
705
735
|
async _retrySoapCall(soapCall) {
|
|
706
736
|
soapCall.retry = false;
|
|
737
|
+
soapCall._retryCount = soapCall._retryCount + 1;
|
|
707
738
|
var newClient = await this._refreshClient(this);
|
|
708
739
|
soapCall.finalize(newClient._soapEndPoint(), newClient);
|
|
709
740
|
if (this._traceAPICalls) {
|
|
@@ -778,6 +809,18 @@ class Client {
|
|
|
778
809
|
this._securityToken = "";
|
|
779
810
|
const credentials = this._connectionParameters._credentials;
|
|
780
811
|
|
|
812
|
+
const sdkVersion = this.sdk.getSDKVersion();
|
|
813
|
+
const version = `${sdkVersion.name} ${sdkVersion.version}`;
|
|
814
|
+
const clientApp = this._connectionParameters._options.clientApp;
|
|
815
|
+
if (!this._connectionParameters._options.noSDKHeaders) {
|
|
816
|
+
this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Version"] = version;
|
|
817
|
+
this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type}`;
|
|
818
|
+
if (clientApp)
|
|
819
|
+
this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Client-App"] = clientApp;
|
|
820
|
+
}
|
|
821
|
+
// See NEO-35259
|
|
822
|
+
this._connectionParameters._options.extraHttpHeaders['X-Query-Source'] = `${version}${clientApp? "," + clientApp : ""}`;
|
|
823
|
+
|
|
781
824
|
// Clear session token cookie to ensure we're not inheriting an expired cookie. See NEO-26589
|
|
782
825
|
if (credentials._type != "SecurityToken" && typeof document != "undefined") {
|
|
783
826
|
document.cookie = '__sessiontoken=;path=/;';
|
|
@@ -790,8 +833,8 @@ class Client {
|
|
|
790
833
|
that.application = new Application(that);
|
|
791
834
|
return Promise.resolve();
|
|
792
835
|
}
|
|
793
|
-
else if (credentials._type == "SecurityToken") {
|
|
794
|
-
|
|
836
|
+
else if (credentials._type == "SecurityToken") {
|
|
837
|
+
that._sessionInfo = undefined;
|
|
795
838
|
that._installedPackages = {};
|
|
796
839
|
that._sessionToken = "";
|
|
797
840
|
that._securityToken = credentials._securityToken;
|
|
@@ -799,12 +842,14 @@ class Client {
|
|
|
799
842
|
return Promise.resolve();
|
|
800
843
|
}
|
|
801
844
|
else if (credentials._type == "UserPassword" || credentials._type == "BearerToken") {
|
|
802
|
-
const soapCall = that._prepareSoapCall("xtk:session", credentials._type === "UserPassword" ? "Logon" : "BearerTokenLogon");
|
|
845
|
+
const soapCall = that._prepareSoapCall("xtk:session", credentials._type === "UserPassword" ? "Logon" : "BearerTokenLogon", false, this._connectionParameters._options.extraHttpHeaders);
|
|
803
846
|
// No retry for logon SOAP methods
|
|
804
847
|
soapCall.retry = false;
|
|
805
848
|
if (credentials._type == "UserPassword") {
|
|
806
849
|
const user = credentials._getUser();
|
|
807
850
|
const password = credentials._getPassword();
|
|
851
|
+
if (!this._connectionParameters._options.noSDKHeaders)
|
|
852
|
+
this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type} ${user}`;
|
|
808
853
|
soapCall.writeString("login", user);
|
|
809
854
|
soapCall.writeString("password", password);
|
|
810
855
|
var parameters = null;
|
|
@@ -872,7 +917,7 @@ class Client {
|
|
|
872
917
|
if (!that.isLogged()) return;
|
|
873
918
|
const credentials = this._connectionParameters._credentials;
|
|
874
919
|
if (credentials._type != "SessionToken" && credentials._type != "AnonymousUser") {
|
|
875
|
-
var soapCall = that._prepareSoapCall("xtk:session", "Logoff");
|
|
920
|
+
var soapCall = that._prepareSoapCall("xtk:session", "Logoff", false, this._connectionParameters._options.extraHttpHeaders);
|
|
876
921
|
return this._makeSoapCall(soapCall).then(function() {
|
|
877
922
|
that._sessionToken = "";
|
|
878
923
|
that._securityToken = "";
|
|
@@ -977,7 +1022,7 @@ class Client {
|
|
|
977
1022
|
* @returns {boolean} a boolean indicating if the package is installed or not
|
|
978
1023
|
*/
|
|
979
1024
|
hasPackage(packageId, optionalName) {
|
|
980
|
-
if (optionalName
|
|
1025
|
+
if (optionalName !== undefined)
|
|
981
1026
|
packageId = `${packageId}:${optionalName}`;
|
|
982
1027
|
if (!this.isLogged())
|
|
983
1028
|
throw CampaignException.NOT_LOGGED_IN(undefined, `Cannot call hasPackage: session not connected`);
|
|
@@ -991,7 +1036,7 @@ class Client {
|
|
|
991
1036
|
* @private
|
|
992
1037
|
* @deprecated since version 1.0.0
|
|
993
1038
|
*/
|
|
994
|
-
|
|
1039
|
+
async _getSecretKeyCipher() {
|
|
995
1040
|
var that = this;
|
|
996
1041
|
if (this._secretKeyCipher) return this._secretKeyCipher;
|
|
997
1042
|
return that.getOption("XtkSecretKey").then(function(secretKey) {
|
|
@@ -1014,7 +1059,7 @@ class Client {
|
|
|
1014
1059
|
*/
|
|
1015
1060
|
async getEntityIfMoreRecent(entityType, fullName, representation, internal) {
|
|
1016
1061
|
const that = this;
|
|
1017
|
-
const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", internal);
|
|
1062
|
+
const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", internal, this._connectionParameters._options.extraHttpHeaders);
|
|
1018
1063
|
soapCall.writeString("pk", entityType + "|" + fullName);
|
|
1019
1064
|
soapCall.writeString("md5", "");
|
|
1020
1065
|
soapCall.writeBoolean("mustExist", false);
|
|
@@ -1117,7 +1162,7 @@ class Client {
|
|
|
1117
1162
|
// console.log(method.toXMLString());
|
|
1118
1163
|
|
|
1119
1164
|
var urn = that._methodCache.getSoapUrn(schemaId, methodName);
|
|
1120
|
-
var soapCall = that._prepareSoapCall(urn, methodName);
|
|
1165
|
+
var soapCall = that._prepareSoapCall(urn, methodName, false, callContext.headers);
|
|
1121
1166
|
|
|
1122
1167
|
// If method is called with one parameter which is a function, then we assume it's a hook: the function will return
|
|
1123
1168
|
// the actual list of parameters
|
|
@@ -1158,6 +1203,8 @@ class Client {
|
|
|
1158
1203
|
soapCall.writeByte(paramName, XtkCaster.asByte(paramValue));
|
|
1159
1204
|
else if (type == "short")
|
|
1160
1205
|
soapCall.writeShort(paramName, XtkCaster.asShort(paramValue));
|
|
1206
|
+
else if (type == "int")
|
|
1207
|
+
soapCall.writeLong(paramName, XtkCaster.asLong(paramValue));
|
|
1161
1208
|
else if (type == "long")
|
|
1162
1209
|
soapCall.writeLong(paramName, XtkCaster.asLong(paramValue));
|
|
1163
1210
|
else if (type == "int64")
|
|
@@ -1182,6 +1229,7 @@ class Client {
|
|
|
1182
1229
|
const index = xtkschema.indexOf(":");
|
|
1183
1230
|
docName = xtkschema.substr(index+1);
|
|
1184
1231
|
}
|
|
1232
|
+
if (!docName) docName = paramName; // Use te parameter name as the XML root element
|
|
1185
1233
|
var xmlValue = that._fromRepresentation(docName, paramValue, callContext.representation);
|
|
1186
1234
|
if (type == "DOMDocument")
|
|
1187
1235
|
soapCall.writeDocument(paramName, xmlValue);
|
|
@@ -1321,8 +1369,11 @@ class Client {
|
|
|
1321
1369
|
*/
|
|
1322
1370
|
async test() {
|
|
1323
1371
|
const request = {
|
|
1324
|
-
url: `${this._connectionParameters._endpoint}/r/test
|
|
1372
|
+
url: `${this._connectionParameters._endpoint}/r/test`,
|
|
1373
|
+
headers: {}
|
|
1325
1374
|
};
|
|
1375
|
+
for (let h in this._connectionParameters._options.extraHttpHeaders)
|
|
1376
|
+
request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
|
|
1326
1377
|
const body = await this._makeHttpCall(request);
|
|
1327
1378
|
const xml = DomUtil.parse(body);
|
|
1328
1379
|
const result = this._toRepresentation(xml);
|
|
@@ -1342,6 +1393,8 @@ class Client {
|
|
|
1342
1393
|
'Cookie': '__sessiontoken=' + this._sessionToken
|
|
1343
1394
|
}
|
|
1344
1395
|
};
|
|
1396
|
+
for (let h in this._connectionParameters._options.extraHttpHeaders)
|
|
1397
|
+
request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
|
|
1345
1398
|
const body = await this._makeHttpCall(request);
|
|
1346
1399
|
const lines = body.split('\n');
|
|
1347
1400
|
const doc = DomUtil.newDocument("ping");
|
|
@@ -1371,6 +1424,8 @@ class Client {
|
|
|
1371
1424
|
'Cookie': '__sessiontoken=' + this._sessionToken
|
|
1372
1425
|
}
|
|
1373
1426
|
};
|
|
1427
|
+
for (let h in this._connectionParameters._options.extraHttpHeaders)
|
|
1428
|
+
request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
|
|
1374
1429
|
const body = await this._makeHttpCall(request);
|
|
1375
1430
|
const lines = body.split('\n');
|
|
1376
1431
|
const doc = DomUtil.newDocument("ping");
|
package/src/soap.js
CHANGED
|
@@ -79,11 +79,12 @@ const NS_XSD = "http://www.w3.org/2001/XMLSchema";
|
|
|
79
79
|
* @param {string} securityToken Campaign security token
|
|
80
80
|
* @param {string} userAgentString The user agent string to use for HTTP requests
|
|
81
81
|
* @param {string} charset The charset encoding used for http requests, usually UTF-8
|
|
82
|
+
* @param {{ name:string, value:string}} extraHttpHeaders key/value pair of HTTP header (will override any other headers)
|
|
82
83
|
* @memberof SOAP
|
|
83
84
|
*/
|
|
84
85
|
class SoapMethodCall {
|
|
85
86
|
|
|
86
|
-
constructor(transport, urn, methodName, sessionToken, securityToken, userAgentString, charset) {
|
|
87
|
+
constructor(transport, urn, methodName, sessionToken, securityToken, userAgentString, charset, extraHttpHeaders) {
|
|
87
88
|
this.request = undefined; // The HTTP request (object litteral passed to the transport layer)
|
|
88
89
|
this.response = undefined; // The HTTP response object (in case of success)
|
|
89
90
|
|
|
@@ -96,11 +97,13 @@ class SoapMethodCall {
|
|
|
96
97
|
this.internal = false;
|
|
97
98
|
// Enable soap retry
|
|
98
99
|
this.retry = true;
|
|
100
|
+
this._retryCount = 0;
|
|
99
101
|
|
|
100
102
|
this._sessionToken = sessionToken || "";
|
|
101
103
|
this._securityToken = securityToken || "";
|
|
102
104
|
this._userAgentString = userAgentString;
|
|
103
105
|
this._charset = charset || "";
|
|
106
|
+
this._extraHttpHeaders = extraHttpHeaders || {};
|
|
104
107
|
|
|
105
108
|
// THe SOAP call being built
|
|
106
109
|
this._doc = undefined; // XML document for SOAP call
|
|
@@ -213,7 +216,7 @@ class SoapMethodCall {
|
|
|
213
216
|
* @param {string} tag the parameter name
|
|
214
217
|
* @param {*} value the parameter value, which will be casted to a int32 according to xtk rules
|
|
215
218
|
*/
|
|
216
|
-
|
|
219
|
+
writeLong(tag, value) {
|
|
217
220
|
value = XtkCaster.asLong(value);
|
|
218
221
|
this._addNode(tag, "xsd:int", XtkCaster.asString(value), SOAP_ENCODING_NATIVE);
|
|
219
222
|
}
|
|
@@ -299,7 +302,8 @@ class SoapMethodCall {
|
|
|
299
302
|
writeDocument(tag, document) {
|
|
300
303
|
const node = this._addNode(tag, "", null, SOAP_ENCODING_XML);
|
|
301
304
|
if (document !== null && document !== undefined) {
|
|
302
|
-
const
|
|
305
|
+
const element = document.nodeType === 1 ? document : document.documentElement;
|
|
306
|
+
const child = this._doc.importNode(element, true);
|
|
303
307
|
node.appendChild(child);
|
|
304
308
|
}
|
|
305
309
|
}
|
|
@@ -515,20 +519,36 @@ class SoapMethodCall {
|
|
|
515
519
|
*/
|
|
516
520
|
_createHTTPRequest(url) {
|
|
517
521
|
|
|
522
|
+
const headers = {
|
|
523
|
+
'Content-type': `application/soap+xml${this._charset ? ";charset=" + this._charset : ""}`,
|
|
524
|
+
'SoapAction': `${this.urn}#${this.methodName}`,
|
|
525
|
+
'X-Security-Token': this._securityToken
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
// Add HTTP headers specific to the SOAP call for better tracing/troubleshooting
|
|
529
|
+
if (this._extraHttpHeaders && this._extraHttpHeaders['ACC-SDK-Version']) {
|
|
530
|
+
// "this.retry" means that the call can be retried, not that it is being retried. The HTTP header howerver, indicates that this
|
|
531
|
+
// is actually a retry of a previously failed call (expired token)
|
|
532
|
+
if (this._retryCount > 0) headers["ACC-SDK-Call-RetryCount"] = `${this._retryCount}`;
|
|
533
|
+
if (this.internal) headers["ACC-SDK-Call-Internal"] = "1";
|
|
534
|
+
}
|
|
535
|
+
|
|
518
536
|
const options = {
|
|
519
537
|
url: url,
|
|
520
538
|
method: 'POST',
|
|
521
|
-
headers:
|
|
522
|
-
'Content-type': `application/soap+xml${this._charset ? ";charset=" + this._charset : ""}`,
|
|
523
|
-
'SoapAction': `${this.urn}#${this.methodName}`,
|
|
524
|
-
'X-Security-Token': this._securityToken
|
|
525
|
-
},
|
|
539
|
+
headers: headers,
|
|
526
540
|
data: DomUtil.toXMLString(this._doc)
|
|
527
541
|
};
|
|
528
542
|
if (this._sessionToken)
|
|
529
543
|
options.headers.Cookie = '__sessiontoken=' + this._sessionToken;
|
|
530
544
|
if (this._userAgentString)
|
|
531
545
|
options.headers['User-Agent'] = this._userAgentString;
|
|
546
|
+
|
|
547
|
+
// Override http headers with custom headers
|
|
548
|
+
for (let h in this._extraHttpHeaders) {
|
|
549
|
+
options.headers[h] = this._extraHttpHeaders[h];
|
|
550
|
+
}
|
|
551
|
+
|
|
532
552
|
return options;
|
|
533
553
|
}
|
|
534
554
|
|
|
@@ -56,12 +56,12 @@ describe('ACC Client (has package)', () => {
|
|
|
56
56
|
client._transport.mockReturnValueOnce(LOGON_RESPONSE);
|
|
57
57
|
await client.NLWS.xtkSession.logon();
|
|
58
58
|
|
|
59
|
-
expect(client.hasPackage("nms:campaign"));
|
|
60
|
-
expect(client.hasPackage("nms", "campaign"));
|
|
61
|
-
expect(
|
|
62
|
-
expect(
|
|
63
|
-
expect(client.hasPackage("nms:core"));
|
|
64
|
-
expect(client.hasPackage("nms", "core"));
|
|
59
|
+
expect(client.hasPackage("nms:campaign")).toBeTruthy();
|
|
60
|
+
expect(client.hasPackage("nms", "campaign")).toBeTruthy();
|
|
61
|
+
expect(client.hasPackage("nms:mrm")).toBeFalsy();
|
|
62
|
+
expect(client.hasPackage("nms", "mrm")).toBeFalsy();
|
|
63
|
+
expect(client.hasPackage("nms:core")).toBeTruthy();
|
|
64
|
+
expect(client.hasPackage("nms", "core")).toBeTruthy();
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
it('should fail when unlogged', async () => {
|
package/test/client.test.js
CHANGED
|
@@ -2283,15 +2283,15 @@ describe('ACC Client', function () {
|
|
|
2283
2283
|
it("Should ignore protocol for local storage root key", async () => {
|
|
2284
2284
|
var connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", {});
|
|
2285
2285
|
var client = await sdk.init(connectionParameters);
|
|
2286
|
-
expect(client._optionCache._storage._rootKey).toBe("acc.js.sdk.1.1.
|
|
2286
|
+
expect(client._optionCache._storage._rootKey).toBe("acc.js.sdk.1.1.3.acc-sdk:8080.cache.OptionCache$");
|
|
2287
2287
|
|
|
2288
2288
|
connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("https://acc-sdk:8080", "admin", "admin", {});
|
|
2289
2289
|
client = await sdk.init(connectionParameters);
|
|
2290
|
-
expect(client._optionCache._storage._rootKey).toBe("acc.js.sdk.1.1.
|
|
2290
|
+
expect(client._optionCache._storage._rootKey).toBe("acc.js.sdk.1.1.3.acc-sdk:8080.cache.OptionCache$");
|
|
2291
2291
|
|
|
2292
2292
|
connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("acc-sdk:8080", "admin", "admin", {});
|
|
2293
2293
|
client = await sdk.init(connectionParameters);
|
|
2294
|
-
expect(client._optionCache._storage._rootKey).toBe("acc.js.sdk.1.1.
|
|
2294
|
+
expect(client._optionCache._storage._rootKey).toBe("acc.js.sdk.1.1.3.acc-sdk:8080.cache.OptionCache$");
|
|
2295
2295
|
})
|
|
2296
2296
|
|
|
2297
2297
|
it("Should support no storage", async () => {
|
|
@@ -2474,4 +2474,333 @@ describe('ACC Client', function () {
|
|
|
2474
2474
|
expect(json).toBe('{"#text":[],"extAccount":[{"id":"1816","name":"defaultPopAccount"},{"id":"1818","name":"defaultOther"},{"id":"1849","name":"billingReport"},{"id":"12070","name":"TST_EXT_ACCOUNT_POSTGRESQL"},{"id":"1817","name":"defaultEmailBulk"},{"id":"2087","name":"ffda"},{"id":"2088","name":"defaultEmailMid"}]}');
|
|
2475
2475
|
});
|
|
2476
2476
|
});
|
|
2477
|
+
|
|
2478
|
+
describe('Support for int type parameters such as nms:extAccount#UpdateMCSynchWkf', () => {
|
|
2479
|
+
it("Should call nms:extAccount#UpdateMCSynchWkf", async () => {
|
|
2480
|
+
const client = await Mock.makeClient();
|
|
2481
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2482
|
+
await client.NLWS.xtkSession.logon();
|
|
2483
|
+
|
|
2484
|
+
client._transport.mockReturnValueOnce(Promise.resolve(`<?xml version='1.0'?>
|
|
2485
|
+
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:wpp:default' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
2486
|
+
<SOAP-ENV:Body>
|
|
2487
|
+
<GetEntityIfMoreRecentResponse xmlns='urn:wpp:default' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
2488
|
+
<pdomDoc xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
|
|
2489
|
+
<schema name="extAccount" namespace="nms" xtkschema="xtk:schema">
|
|
2490
|
+
<element name="extAccount"></element>
|
|
2491
|
+
<methods>
|
|
2492
|
+
<method library="nms:messageCenter.js" name="UpdateMCSynchWkf" static="true" hidden="true">
|
|
2493
|
+
<parameters>
|
|
2494
|
+
<param name="extAccountId" type="int" desc="Message Center external account identifier"/>
|
|
2495
|
+
</parameters>
|
|
2496
|
+
</method>
|
|
2497
|
+
</methods>
|
|
2498
|
+
</schema>
|
|
2499
|
+
</pdomDoc>
|
|
2500
|
+
</GetEntityIfMoreRecentResponse>
|
|
2501
|
+
</SOAP-ENV:Body>
|
|
2502
|
+
</SOAP-ENV:Envelope>`));
|
|
2503
|
+
|
|
2504
|
+
client._transport.mockReturnValueOnce(Promise.resolve(`<?xml version='1.0'?>
|
|
2505
|
+
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:nms:extAccount' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
2506
|
+
<SOAP-ENV:Body>
|
|
2507
|
+
<UpdateMCSynchWkfResponse xmlns='urn:nms:extAccount' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
2508
|
+
</UpdateMCSynchWkfResponse>
|
|
2509
|
+
</SOAP-ENV:Body>
|
|
2510
|
+
</SOAP-ENV:Envelope>`));
|
|
2511
|
+
|
|
2512
|
+
await client.NLWS.nmsExtAccount.updateMCSynchWkf(1);
|
|
2513
|
+
})
|
|
2514
|
+
});
|
|
2515
|
+
|
|
2516
|
+
describe("Method-level HTTP headers", () => {
|
|
2517
|
+
it("Should set header", async () => {
|
|
2518
|
+
const client = await Mock.makeClient();
|
|
2519
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2520
|
+
await client.NLWS.xtkSession.logon();
|
|
2521
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_QUERY_SCHEMA_RESPONSE);
|
|
2522
|
+
client._transport.mockReturnValueOnce(Mock.GET_QUERY_EXECUTE_RESPONSE);
|
|
2523
|
+
const queryDef = {
|
|
2524
|
+
"schema": "nms:extAccount",
|
|
2525
|
+
"operation": "select",
|
|
2526
|
+
"select": {
|
|
2527
|
+
"node": [
|
|
2528
|
+
{ "expr": "@id" },
|
|
2529
|
+
{ "expr": "@name" }
|
|
2530
|
+
]
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2533
|
+
const query = client.NLWS.headers({'X-Test': 'hello'}).xtkQueryDef.create(queryDef);
|
|
2534
|
+
|
|
2535
|
+
let headers = {};
|
|
2536
|
+
client.registerObserver({
|
|
2537
|
+
onSOAPCall: (soapCall) => {
|
|
2538
|
+
const request = soapCall.request;
|
|
2539
|
+
headers = request.headers;
|
|
2540
|
+
}
|
|
2541
|
+
});
|
|
2542
|
+
await query.executeQuery();
|
|
2543
|
+
expect(headers).toMatchObject({
|
|
2544
|
+
"SoapAction": "xtk:queryDef#ExecuteQuery",
|
|
2545
|
+
"X-Test": "hello"
|
|
2546
|
+
});
|
|
2547
|
+
});
|
|
2548
|
+
|
|
2549
|
+
it("Should support global and method-level http headers", async () => {
|
|
2550
|
+
const client = await Mock.makeClient({
|
|
2551
|
+
extraHttpHeaders: {
|
|
2552
|
+
"X-Test": "world",
|
|
2553
|
+
"X-Test-Global": "global"
|
|
2554
|
+
}
|
|
2555
|
+
});
|
|
2556
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2557
|
+
await client.NLWS.xtkSession.logon();
|
|
2558
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_QUERY_SCHEMA_RESPONSE);
|
|
2559
|
+
client._transport.mockReturnValueOnce(Mock.GET_QUERY_EXECUTE_RESPONSE);
|
|
2560
|
+
const queryDef = {
|
|
2561
|
+
"schema": "nms:extAccount",
|
|
2562
|
+
"operation": "select",
|
|
2563
|
+
"select": {
|
|
2564
|
+
"node": [
|
|
2565
|
+
{ "expr": "@id" },
|
|
2566
|
+
{ "expr": "@name" }
|
|
2567
|
+
]
|
|
2568
|
+
}
|
|
2569
|
+
};
|
|
2570
|
+
const query = client.NLWS.headers({'X-Test': 'hello'}).xtkQueryDef.create(queryDef);
|
|
2571
|
+
|
|
2572
|
+
let headers = {};
|
|
2573
|
+
client.registerObserver({
|
|
2574
|
+
onSOAPCall: (soapCall) => {
|
|
2575
|
+
const request = soapCall.request;
|
|
2576
|
+
headers = request.headers;
|
|
2577
|
+
}
|
|
2578
|
+
});
|
|
2579
|
+
await query.executeQuery();
|
|
2580
|
+
expect(headers).toMatchObject({
|
|
2581
|
+
"SoapAction": "xtk:queryDef#ExecuteQuery",
|
|
2582
|
+
"X-Test": "hello",
|
|
2583
|
+
"X-Test-Global": "global"
|
|
2584
|
+
});
|
|
2585
|
+
})
|
|
2586
|
+
|
|
2587
|
+
it("Should support undefined method headers", async () => {
|
|
2588
|
+
const client = await Mock.makeClient({
|
|
2589
|
+
extraHttpHeaders: {
|
|
2590
|
+
"X-Test": "world",
|
|
2591
|
+
"X-Test-Global": "global"
|
|
2592
|
+
}
|
|
2593
|
+
});
|
|
2594
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2595
|
+
await client.NLWS.xtkSession.logon();
|
|
2596
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_QUERY_SCHEMA_RESPONSE);
|
|
2597
|
+
client._transport.mockReturnValueOnce(Mock.GET_QUERY_EXECUTE_RESPONSE);
|
|
2598
|
+
const queryDef = {
|
|
2599
|
+
"schema": "nms:extAccount",
|
|
2600
|
+
"operation": "select",
|
|
2601
|
+
"select": {
|
|
2602
|
+
"node": [
|
|
2603
|
+
{ "expr": "@id" },
|
|
2604
|
+
{ "expr": "@name" }
|
|
2605
|
+
]
|
|
2606
|
+
}
|
|
2607
|
+
};
|
|
2608
|
+
// missing headers
|
|
2609
|
+
const query = client.NLWS.headers().xtkQueryDef.create(queryDef);
|
|
2610
|
+
|
|
2611
|
+
let headers = {};
|
|
2612
|
+
client.registerObserver({
|
|
2613
|
+
onSOAPCall: (soapCall) => {
|
|
2614
|
+
const request = soapCall.request;
|
|
2615
|
+
headers = request.headers;
|
|
2616
|
+
}
|
|
2617
|
+
});
|
|
2618
|
+
await query.executeQuery();
|
|
2619
|
+
expect(headers).toMatchObject({
|
|
2620
|
+
"SoapAction": "xtk:queryDef#ExecuteQuery",
|
|
2621
|
+
"X-Test": "world",
|
|
2622
|
+
"X-Test-Global": "global"
|
|
2623
|
+
});
|
|
2624
|
+
})
|
|
2625
|
+
|
|
2626
|
+
it("Should set http headers with an xml representation", async () => {
|
|
2627
|
+
const client = await Mock.makeClient();
|
|
2628
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2629
|
+
await client.NLWS.xtkSession.logon();
|
|
2630
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_QUERY_SCHEMA_RESPONSE);
|
|
2631
|
+
client._transport.mockReturnValueOnce(Mock.GET_QUERY_EXECUTE_RESPONSE);
|
|
2632
|
+
const queryDef = DomUtil.parse(`
|
|
2633
|
+
<queryDef schema="nms:extAccount" operation="select">
|
|
2634
|
+
<select>
|
|
2635
|
+
<node expr="@id"/>
|
|
2636
|
+
<node expr="@name"/>
|
|
2637
|
+
</select>
|
|
2638
|
+
</queryDef>
|
|
2639
|
+
`);
|
|
2640
|
+
const query = client.NLWS
|
|
2641
|
+
.headers({'X-Test': 'hello', 'X-Test-Before': 'before'})
|
|
2642
|
+
.xml
|
|
2643
|
+
.headers({'X-Test': 'world', 'X-Test-After': 'after'})
|
|
2644
|
+
.xtkQueryDef.create(queryDef);
|
|
2645
|
+
let headers = {};
|
|
2646
|
+
client.registerObserver({
|
|
2647
|
+
onSOAPCall: (soapCall) => {
|
|
2648
|
+
const request = soapCall.request;
|
|
2649
|
+
headers = request.headers;
|
|
2650
|
+
}
|
|
2651
|
+
});
|
|
2652
|
+
await query.executeQuery();
|
|
2653
|
+
console.log(headers);
|
|
2654
|
+
expect(headers).toMatchObject({
|
|
2655
|
+
"SoapAction": "xtk:queryDef#ExecuteQuery",
|
|
2656
|
+
"X-Test": "world",
|
|
2657
|
+
"X-Test-Before": "before",
|
|
2658
|
+
"X-Test-After": "after"
|
|
2659
|
+
});
|
|
2660
|
+
});
|
|
2661
|
+
});
|
|
2662
|
+
|
|
2663
|
+
describe("ACC-SDK HTTP headers", () => {
|
|
2664
|
+
|
|
2665
|
+
const collectHeaders = async (client, callback) => {
|
|
2666
|
+
let headers = {};
|
|
2667
|
+
client.registerObserver({
|
|
2668
|
+
onSOAPCall: (soapCall) => {
|
|
2669
|
+
const request = soapCall.request;
|
|
2670
|
+
headers = request.headers;
|
|
2671
|
+
},
|
|
2672
|
+
onHTTPCall: (request) => {
|
|
2673
|
+
headers = request.headers;
|
|
2674
|
+
}
|
|
2675
|
+
});
|
|
2676
|
+
await callback();
|
|
2677
|
+
return headers;
|
|
2678
|
+
};
|
|
2679
|
+
|
|
2680
|
+
it("Should set headers by default", async () => {
|
|
2681
|
+
const client = await Mock.makeClient();
|
|
2682
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2683
|
+
await client.NLWS.xtkSession.logon();
|
|
2684
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_QUERY_SCHEMA_RESPONSE);
|
|
2685
|
+
client._transport.mockReturnValueOnce(Mock.GET_QUERY_EXECUTE_RESPONSE);
|
|
2686
|
+
const queryDef = {
|
|
2687
|
+
"schema": "nms:extAccount",
|
|
2688
|
+
"operation": "select",
|
|
2689
|
+
"select": {
|
|
2690
|
+
"node": [
|
|
2691
|
+
{ "expr": "@id" },
|
|
2692
|
+
{ "expr": "@name" }
|
|
2693
|
+
]
|
|
2694
|
+
}
|
|
2695
|
+
};
|
|
2696
|
+
const query = client.NLWS.xtkQueryDef.create(queryDef);
|
|
2697
|
+
|
|
2698
|
+
const headers = await collectHeaders(client, async() => {
|
|
2699
|
+
await query.executeQuery();
|
|
2700
|
+
});
|
|
2701
|
+
|
|
2702
|
+
expect(headers).toMatchObject({
|
|
2703
|
+
"ACC-SDK-Version": `${sdk.getSDKVersion().name} ${sdk.getSDKVersion().version}`,
|
|
2704
|
+
"ACC-SDK-Auth": "UserPassword admin",
|
|
2705
|
+
"X-Query-Source": `${sdk.getSDKVersion().name} ${sdk.getSDKVersion().version}`,
|
|
2706
|
+
});
|
|
2707
|
+
// This header is only set if "clientApp" connection parameter is set
|
|
2708
|
+
expect(headers["ACC-SDK-Client-App"]).toBeUndefined();
|
|
2709
|
+
});
|
|
2710
|
+
|
|
2711
|
+
it("Should disable ACC-SDK headers", async () => {
|
|
2712
|
+
const client = await Mock.makeClient({
|
|
2713
|
+
noSDKHeaders: true
|
|
2714
|
+
});
|
|
2715
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2716
|
+
await client.NLWS.xtkSession.logon();
|
|
2717
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_QUERY_SCHEMA_RESPONSE);
|
|
2718
|
+
client._transport.mockReturnValueOnce(Mock.GET_QUERY_EXECUTE_RESPONSE);
|
|
2719
|
+
const queryDef = {
|
|
2720
|
+
"schema": "nms:extAccount",
|
|
2721
|
+
"operation": "select",
|
|
2722
|
+
"select": {
|
|
2723
|
+
"node": [
|
|
2724
|
+
{ "expr": "@id" },
|
|
2725
|
+
{ "expr": "@name" }
|
|
2726
|
+
]
|
|
2727
|
+
}
|
|
2728
|
+
};
|
|
2729
|
+
const query = client.NLWS.xtkQueryDef.create(queryDef);
|
|
2730
|
+
|
|
2731
|
+
const headers = await collectHeaders(client, async() => {
|
|
2732
|
+
await query.executeQuery();
|
|
2733
|
+
});
|
|
2734
|
+
expect(headers["ACC-SDK-Version"]).toBeUndefined();
|
|
2735
|
+
expect(headers["ACC-SDK-Auth"]).toBeUndefined();
|
|
2736
|
+
expect(headers["X-Query-Source"]).toBe(`${sdk.getSDKVersion().name} ${sdk.getSDKVersion().version}`);
|
|
2737
|
+
});
|
|
2738
|
+
|
|
2739
|
+
it("Should support ACC-SDK-Client-App header", async () => {
|
|
2740
|
+
const client = await Mock.makeClient({
|
|
2741
|
+
clientApp: 'Test client app'
|
|
2742
|
+
});
|
|
2743
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2744
|
+
await client.NLWS.xtkSession.logon();
|
|
2745
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_QUERY_SCHEMA_RESPONSE);
|
|
2746
|
+
client._transport.mockReturnValueOnce(Mock.GET_QUERY_EXECUTE_RESPONSE);
|
|
2747
|
+
const queryDef = {
|
|
2748
|
+
"schema": "nms:extAccount",
|
|
2749
|
+
"operation": "select",
|
|
2750
|
+
"select": {
|
|
2751
|
+
"node": [
|
|
2752
|
+
{ "expr": "@id" },
|
|
2753
|
+
{ "expr": "@name" }
|
|
2754
|
+
]
|
|
2755
|
+
}
|
|
2756
|
+
};
|
|
2757
|
+
const query = client.NLWS.xtkQueryDef.create(queryDef);
|
|
2758
|
+
|
|
2759
|
+
const headers = await collectHeaders(client, async() => {
|
|
2760
|
+
await query.executeQuery();
|
|
2761
|
+
});
|
|
2762
|
+
expect(headers).toMatchObject({
|
|
2763
|
+
"ACC-SDK-Version": `${sdk.getSDKVersion().name} ${sdk.getSDKVersion().version}`,
|
|
2764
|
+
"ACC-SDK-Auth": "UserPassword admin",
|
|
2765
|
+
"ACC-SDK-Client-App": "Test client app",
|
|
2766
|
+
"X-Query-Source": `${sdk.getSDKVersion().name} ${sdk.getSDKVersion().version},Test client app`,
|
|
2767
|
+
});
|
|
2768
|
+
});
|
|
2769
|
+
|
|
2770
|
+
it("Should set ACC-SDK headers on ping JSP", async () => {
|
|
2771
|
+
const client = await Mock.makeClient({
|
|
2772
|
+
clientApp: 'Test client app'
|
|
2773
|
+
});
|
|
2774
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2775
|
+
await client.NLWS.xtkSession.logon();
|
|
2776
|
+
const headers = await collectHeaders(client, async() => {
|
|
2777
|
+
client._transport.mockReturnValueOnce(Mock.PING);
|
|
2778
|
+
await client.ping();
|
|
2779
|
+
});
|
|
2780
|
+
expect(headers).toMatchObject({
|
|
2781
|
+
"ACC-SDK-Version": `${sdk.getSDKVersion().name} ${sdk.getSDKVersion().version}`,
|
|
2782
|
+
"ACC-SDK-Auth": "UserPassword admin",
|
|
2783
|
+
"ACC-SDK-Client-App": "Test client app",
|
|
2784
|
+
"X-Query-Source": `${sdk.getSDKVersion().name} ${sdk.getSDKVersion().version},Test client app`,
|
|
2785
|
+
});
|
|
2786
|
+
});
|
|
2787
|
+
|
|
2788
|
+
it("Should set ACC-SDK headers on mcping JSP", async () => {
|
|
2789
|
+
const client = await Mock.makeClient({
|
|
2790
|
+
clientApp: 'Test client app'
|
|
2791
|
+
});
|
|
2792
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2793
|
+
await client.NLWS.xtkSession.logon();
|
|
2794
|
+
const headers = await collectHeaders(client, async() => {
|
|
2795
|
+
client._transport.mockReturnValueOnce(Mock.MC_PING);
|
|
2796
|
+
await client.mcPing();
|
|
2797
|
+
});
|
|
2798
|
+
expect(headers).toMatchObject({
|
|
2799
|
+
"ACC-SDK-Version": `${sdk.getSDKVersion().name} ${sdk.getSDKVersion().version}`,
|
|
2800
|
+
"ACC-SDK-Auth": "UserPassword admin",
|
|
2801
|
+
"ACC-SDK-Client-App": "Test client app",
|
|
2802
|
+
"X-Query-Source": `${sdk.getSDKVersion().name} ${sdk.getSDKVersion().version},Test client app`,
|
|
2803
|
+
});
|
|
2804
|
+
});
|
|
2805
|
+
});
|
|
2477
2806
|
});
|
package/test/soap.test.js
CHANGED
|
@@ -25,8 +25,8 @@ const sdk = require('../src/index.js');
|
|
|
25
25
|
|
|
26
26
|
const URL = "https://soap-test/nl/jsp/soaprouter.jsp";
|
|
27
27
|
|
|
28
|
-
function makeSoapMethodCall(transport, urn, methodName, sessionToken, securityToken, userAgentString, optionalCharset) {
|
|
29
|
-
const call = new SoapMethodCall(transport, urn, methodName, sessionToken, securityToken, userAgentString, optionalCharset);
|
|
28
|
+
function makeSoapMethodCall(transport, urn, methodName, sessionToken, securityToken, userAgentString, optionalCharset, charset, extraHttpHeaders) {
|
|
29
|
+
const call = new SoapMethodCall(transport, urn, methodName, sessionToken, securityToken, userAgentString, optionalCharset, charset, extraHttpHeaders);
|
|
30
30
|
return call;
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -388,6 +388,22 @@ describe('SOAP', function() {
|
|
|
388
388
|
expect(actualElement.getAttribute("att")).toBe("Hello");
|
|
389
389
|
});
|
|
390
390
|
|
|
391
|
+
it('Should support passing DOM elements instead of document parameters', function() {
|
|
392
|
+
const xml = '<root att="Hello"><child/></root>';
|
|
393
|
+
const doc = DomUtil.parse(xml);
|
|
394
|
+
|
|
395
|
+
const call = makeSoapMethodCall(undefined, "xtk:session", "Document", "$session$", "$security$");
|
|
396
|
+
call.writeDocument("p", doc.documentElement);
|
|
397
|
+
const request = call._createHTTPRequest(URL);
|
|
398
|
+
const env = DomUtil.parse(request.data).documentElement;
|
|
399
|
+
const body = hasChildElement(env, "SOAP-ENV:Body");
|
|
400
|
+
const method = hasChildElement(body, "m:Document");
|
|
401
|
+
const param = hasChildElement(method, "p");
|
|
402
|
+
const actualElement = hasChildElement(param, "root");
|
|
403
|
+
expect(actualElement).toBeTruthy();
|
|
404
|
+
expect(actualElement.getAttribute("att")).toBe("Hello");
|
|
405
|
+
});
|
|
406
|
+
|
|
391
407
|
it('Should write null document', function() {
|
|
392
408
|
const call = makeSoapMethodCall(undefined, "xtk:session", "Document", "$session$", "$security$");
|
|
393
409
|
call.writeDocument("p", null);
|
|
@@ -850,5 +866,23 @@ describe("Campaign exception", () => {
|
|
|
850
866
|
expect(req.headers["X-Security-Token"].indexOf("$security$")).toBe(-1);
|
|
851
867
|
})
|
|
852
868
|
|
|
869
|
+
describe('Extra Http headers', () => {
|
|
870
|
+
it("Should take additional headers", () => {
|
|
871
|
+
const call = makeSoapMethodCall(undefined, "xtk:session", "Date", "$session$", "$security$", "My User Agent", undefined, { 'X-ACC-UI-Version': '1.0' });
|
|
872
|
+
const request = call._createHTTPRequest(URL);
|
|
873
|
+
expect(request.headers['User-Agent']).toBe("My User Agent");
|
|
874
|
+
expect(request.headers['X-ACC-UI-Version']).toBe("1.0");
|
|
875
|
+
expect(request.headers['SoapAction']).toBe("xtk:session#Date");
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
it("Should override default headers headers", () => {
|
|
879
|
+
const call = makeSoapMethodCall(undefined, "xtk:session", "Date", "$session$", "$security$", "My User Agent", undefined, { 'X-ACC-UI-Version': '1.0', 'SoapAction': 'My soap action' });
|
|
880
|
+
const request = call._createHTTPRequest(URL);
|
|
881
|
+
expect(request.headers['User-Agent']).toBe("My User Agent");
|
|
882
|
+
expect(request.headers['X-ACC-UI-Version']).toBe("1.0");
|
|
883
|
+
expect(request.headers['SoapAction']).toBe("My soap action");
|
|
884
|
+
});
|
|
885
|
+
});
|
|
886
|
+
|
|
853
887
|
});
|
|
854
888
|
|