Home Reference Source

src/data/datasources/SharePoint/SPSoapAdapter/Worker/SoapClient.js

/**
 This Source Code is licensed under the MIT license. If a copy of the
 MIT-license was not distributed with this file, You can obtain one at:
 http://opensource.org/licenses/mit-license.html.

 @author: Hans van den Akker (mysim1)
 @license MIT
 @copyright Bizboard, 2015

 */

import XML2JS               from './xmljs';
import xmljs                from 'xml2js';
import template             from 'lodash/template.js';
import {ObjectHelper}       from '../../../../../utils/ObjectHelper';
import {PostRequest}        from '../../../../../utils/request/RequestClient';
import {ParseStringToXml}   from '../../../../../utils/request/XmlParser';

export class SoapClient {

    constructor() {

        /* Bind all local methods to the current object instance, so we can refer to "this"
         * in the methods as expected, even when they're called from event handlers.        */
        ObjectHelper.bindAllMethods(this, this);

        /* Hide all private properties (starting with '_') and methods from enumeration,
         * so when you do for( in ), only actual data properties show up. */
        ObjectHelper.hideMethodsAndPrivatePropertiesFromObject(this);

        /* Hide the priority field from enumeration, so we don't save it to the dataSource. */
        ObjectHelper.hidePropertyFromObject(Object.getPrototypeOf(this), 'length');
    }


    _applySoapTemplate(properties) {
        return template('<?xml version="1.0" encoding="utf-8"?>' +
            '<soap:Envelope ' +
            '  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
            '  xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' +
            '  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
            '<soap:Body>' +
            '<<%= method %> xmlns="http://schemas.microsoft.com/sharepoint/soap/">' +
            '<%= params %>' +
            '</<%= method %>>' +
            '</soap:Body>' +
            '</soap:Envelope>')(properties);
    }


    _serializeParams(params) {
        if (!params || params.length == 0) return "";
        var data = {"root": params};
        var creator = new XML2JS();
        var payload = creator.json2xml_str(data);

        return payload.replace("<root>", "").replace("</root>", "");
    }

    _handleError(error) {
        return "Error!";
    }

    /**
     * Replaces locally generated item IDs with their remote SharePoint counterparts.
     * @param {String} text Text to replace the IDs in.
     * @param {Array} tempKeys Array of {localId:x, remoteId:y} pairs.
     * @returns {string} Text with the replaced IDs
     * @private
     */
    _replaceTempKeys(text = '', tempKeys = []) {
        for (let tempKey of tempKeys) {
            /* Split/join is faster than doing a regex replace:
             * http://stackoverflow.com/questions/1144783/replacing-all-occurrences-of-a-string-in-javascript#comment27942520_1145525 */
            text = text.split(tempKey.localId).join(tempKey.remoteId);
        }

        return text;
    }

    call(config, tempKeys = []) {

        var request;
        config = config || {};

        request = {
            url: config.url,
            headers: config.headers,
            data: this._applySoapTemplate({
                method: config.method,
                params: this._replaceTempKeys(this._serializeParams(config.params), tempKeys)
            })
        };

        var context = this;
        // Make the request.
        return new Promise(function (resolve, reject) {

            PostRequest(request)
                .then(function (soapresult) {

                    var parseString = xmljs.parseString;
                    parseString(soapresult.response, function (err, result) {
                        resolve({data: result, timestamp: soapresult.timestamp});
                    });

                }, function (error) {
                    reject(context._handleError(error));
                });
        });
    }
}