Reference Source Test

lib/template.js

'use strict';
const https = require('https');
const {
  responseHandler, errorHandler, buildRequestOptions,
} = require('./common');
const {
  remove,
  invite,
  view,
} = require('./document');

/**
 * @type {function}
 * @param {DocumentRemoveParams} data - remove document payload
 * @param {function(err: ApiErrorResponse, res: DocumentRemoveResponse)} [callback] - error first node.js callback
 */
const removeDocument = remove;

/**
 * @type {function}
 * @param {DocumentInviteParams} data - create document invite payload
 * @param {function(err: ApiErrorResponse, res: DocumentInviteResponse)} [callback] - error first node.js callback
 */
const sendDocumentInvite = invite;

/**
 * @type {function}
 * @param {DocumentViewParams} data - view document with field extract payload
 * @param {function(err: ApiErrorResponse, res: DocumentViewResponse)} [callback] - error first node.js callback
 */
const getDocumentDetails = view;

/**
 * Template methods
 */
class Template {

  /**
   * Document invite optional settings
   * @typedef {Object} TemplateCreateOptions
   * @property {boolean} [removeOriginalDocument=false] - if true original document will be removed
   */

  /**
   * Create template payload
   * @typedef {Object} TemplateCreateParams
   * @property {string} document_id - an id of original document
   * @property {string} document_name - a name of new template
   * @property {TemplateCreateOptions} options - create template optional settings
   * @property {string} token - your auth token
   */

  /**
   * Create template response data
   * @typedef {Object} TemplateCreateResponse
   * @property {string} id - an id of created template
   */

  /**
   * Creates a template by copying an existing unfulfilled and not requested for sign document.
   * By default original document is not removed after template creation. To remove original document set `removeOriginalDocument` option to `true`.
   * @param {TemplateCreateParams} data - create template payload
   * @param {function(err: ApiErrorResponse, res: TemplateCreateResponse)} [originalCallback] - error first node.js callback
   */
  static create ({
    document_id,
    document_name,
    options: { removeOriginalDocument = false } = {},
    token,
  }, originalCallback) {
    const JSONData = JSON.stringify({
      document_id,
      document_name,
    });

    const callbackWithDocumentDeletion = (createErr, createRes) => {
      if (createErr) {
        originalCallback(createErr);
        return;
      } else {
        removeDocument({
          id: document_id,
          token,
        }, removeErr => {
          if (removeErr) {
            originalCallback(removeErr);
            return;
          } else {
            originalCallback(null, createRes);
            return;
          }
        });
      }
    };

    const callback = removeOriginalDocument
      ? callbackWithDocumentDeletion
      : originalCallback;

    const req = https
      .request(buildRequestOptions({
        method: 'POST',
        path: '/template',
        authorization: {
          type: 'Bearer',
          token,
        },
        headers: {
          'Content-Type': 'application/json',
          'Content-Length': Buffer.byteLength(JSONData),
        },
      }), responseHandler(callback))
      .on('error', errorHandler(originalCallback));

    req.write(JSONData);
    req.end();
  }

  /**
   * Copy template payload
   * @typedef {Object} TemplateDuplicateParams
   * @property {string} id - an id of original template
   * @property {string} name - a name of new document
   * @property {string} token - your auth token
   */

  /**
   * Copy template response data
   * @typedef {Object} TemplateDuplicateResponse
   * @property {string} id - an id of created document
   * @property {string} name - a name of created document
   */

  /**
   * Creates a new document by copying a template.
   * If a name is not supplied then document name will be set to the original template's name by default.
   * @param {TemplateDuplicateParams} data - duplicate template payload
   * @param {function(err: ApiErrorResponse, res: TemplateDuplicateResponse)} [callback] - error first node.js callback
   */
  static duplicate ({
    id: template_id,
    name: document_name,
    token,
  }, callback) {
    const JSONData = JSON.stringify({
      template_id,
      document_name,
    });

    const req = https
      .request(buildRequestOptions({
        method: 'POST',
        path: `/template/${template_id}/copy`,
        authorization: {
          type: 'Bearer',
          token,
        },
        headers: {
          'Content-Type': 'application/json',
          'Content-Length': Buffer.byteLength(JSONData),
        },
      }), responseHandler(callback))
      .on('error', errorHandler(callback));

    req.write(JSONData);
    req.end();
  }

  /**
   * Create invite with template payload
   * @typedef {DocumentInviteParams} TemplateInviteParams
   */

  /**
   * Create invite with template response data
   * @typedef {DocumentInviteResponse} TemplateInviteResponse
   */

  /**
   * Creates an invite to sign a template.
   * You can create a simple free form invite(s) or a role-based invite(s).
   * The method copies a template into document and creates an invite using created document.
   * @param {TemplateInviteParams} data - create template invite payload
   * @param {function(err: ApiErrorResponse, res: TemplateInviteResponse)} [callback] - error first node.js callback
   */
  static invite ({
    id,
    data,
    options,
    token,
  }, callback) {
    Template.duplicate({
      id,
      token,
    }, (copyErr, copyRes) => {
      if (copyErr) {
        callback(copyErr);
        return;
      } else if (Array.isArray(data.to)) {
        const { id: documentId } = copyRes;

        getDocumentDetails({
          id: documentId,
          token,
        }, (detailErr, detailRes) => {
          if (detailErr) {
            callback(detailErr);
            return;
          } else {
            const inviteData = Object.assign({}, data, { document_id: documentId });
            const { roles } = detailRes;

            for (const signer of inviteData.to) {
              try {
                signer.role_id = roles.find(role => role.name === signer.role).unique_id;
              } catch (err) {
                callback(err);
                return;
              }
            }

            sendDocumentInvite({
              id: documentId,
              data: inviteData,
              options,
              token,
            }, callback);
          }
        });
      } else {
        const { id: documentId } = copyRes;
        const inviteData = Object.assign({}, data, { document_id: documentId });

        sendDocumentInvite({
          id: documentId,
          data: inviteData,
          options,
          token,
        }, callback);
      }
    });
  }

  /**
   * Remove template payload
   * @typedef {DocumentRemoveParams} TemplateRemoveParams
   */

  /**
   * Remove template response data
   * @typedef {DocumentRemoveResponse} TemplateRemoveResponse
   */

  /**
   * Removes a specified template from folder
   * @param {TemplateRemoveParams} data - remove template payload
   * @param {function(err: ApiErrorResponse, res: TemplateRemoveResponse)} [callback] - error first node.js callback
   */
  static remove ({ id, token }, callback) {
    removeDocument({
      id,
      token,
    }, callback);
  }

}

module.exports = Template;