const extend = require('extend');
const Base = require('./base');
const join = require('./deps/utils/join');
const encodePath = require('./deps/utils/encodePath');
const Blob = require('./blob');
const BatchBlob = require('./upload/blob');
const BatchUpload = require('./upload/batch');
const Document = require('./document');
const FormData = require('./deps/form-data');
const isDocument = (obj) => (obj instanceof Document || (typeof obj === 'object' && obj['entity-type'] === 'document'));
/**
* The `Operation` class allows to execute an operation on a Nuxeo Platform instance.
*
* **Cannot directly be instantiated**
*
* @example
* var Nuxeo = require('nuxeo')
* var nuxeo = new Nuxeo({
* baseURL: 'http://localhost:8080/nuxeo',
* auth: {
* method: 'basic',
* username: 'Administrator',
* password: 'Administrator'
* }
* });
* nuxeo.operation('Document.GetChild')
* .input('/default-domain')
* .params({
* name: 'workspaces',
* })
* .execute()
* .then(function(res) {
* // res.uid !== null
* // res.title === 'Workspaces'
* })
* .catch(function(error) {
* throw new Error(error);
* });
*/
class Operation extends Base {
/**
* Creates an Operation.
* @param {string} opts - The configuration options.
* @param {string} opts.nuxeo - The {@link Nuxeo} object linked to this `Operation` object.
* @param {string} opts.id - The ID of the operation.
* @param {string} opts.url - The automation URL.
*/
constructor(opts) {
const options = extend(true, {}, opts);
super(options);
this._nuxeo = options.nuxeo;
this._id = options.id;
this._url = options.url;
this._automationParams = {
params: {},
context: {},
input: undefined,
};
}
/**
* Adds an operation param.
* @param {string} name - The param name.
* @param {string} value - The param value.
* @returns {Operation} The operation itself.
*/
param(name, value) {
this._automationParams.params[name] = value;
return this;
}
/**
* Adds operation params. The given params are merged with the existing ones if any.
* @param {object} params - The params to be merge with the existing ones.
* @returns {Operation} The operation itself.
*/
params(params) {
this._automationParams.params = extend(true, {}, this._automationParams.params, params);
return this;
}
/**
* Sets this operation context.
* @param {object} context - The operation context.
* @returns {Operation} The operation itself.
*/
context(context) {
this._automationParams.context = context;
return this;
}
/**
* Sets this operation input.
* @param {string|Array|Blob|BatchBlob|BatchUpload} input - The operation input.
* @returns {Operation} The operation itself.
*/
input(input) {
this._automationParams.input = input;
return this;
}
/**
* Executes this operation.
* @param {object} [opts] - Options overriding the ones from this object.
* @returns {Promise} A Promise object resolved with the result of the Operation.
*/
execute(opts = {}) {
const options = this._computeOptions(opts);
options.headers = options.headers || {};
options.headers['Content-Type'] = this._computeContentTypeHeader(this._automationParams.input);
let finalOptions = {
method: 'POST',
url: this._computeRequestURL(),
body: this._computeRequestBody(),
};
finalOptions = extend(true, finalOptions, options);
return this._nuxeo.http(finalOptions);
}
_computeContentTypeHeader(input) {
return this._isMultipartInput(input) ? 'multipart/form-data' : 'application/json';
}
_computeRequestURL() {
const { input } = this._automationParams;
if (input instanceof BatchBlob) {
return join(this._nuxeo._restURL, 'upload', input['upload-batch'], input['upload-fileId'], 'execute', this._id);
}
if (input instanceof BatchUpload) {
return join(this._nuxeo._restURL, 'upload', input._batchId, 'execute', this._id);
}
return join(this._url, encodePath(this._id));
}
_computeRequestBody() {
const { input } = this._automationParams;
if (this._isBatchInput(input)) {
// no input needed
const body = extend(true, {}, this._automationParams);
body.input = undefined;
return body;
}
if (input instanceof Array) {
if (input.length > 0) {
const first = input[0];
if (isDocument(first)) {
// assume document list
const docs = input.map((doc) => doc.uid);
this._automationParams.input = `docs:${docs.join(',')}`;
return this._automationParams;
}
if (typeof first === 'string') {
// assume ref list
this._automationParams.input = `docs:${input.join(',')}`;
return this._automationParams;
}
if (first instanceof Blob) {
// blob list => multipart
const automationParams = {
params: this._automationParams.params,
context: this._automationParams.context,
};
const form = new FormData();
form.append('params', JSON.stringify(automationParams));
let inputIndex = 0;
for (const blob of input) {
form.append(`input#${inputIndex}`, blob.content, blob.name);
inputIndex += 1;
}
return form;
}
}
} else if (isDocument(input)) {
this._automationParams.input = input.uid || input;
return this._automationParams;
} else if (input instanceof Blob) {
const automationParams = {
params: this._automationParams.params,
context: this._automationParams.context,
};
const form = new FormData();
form.append('params', JSON.stringify(automationParams));
form.append('input', input.content, input.name);
return form;
}
return this._automationParams;
}
_isMultipartInput(input) {
if (input instanceof Array) {
if (input.length > 0) {
const first = input[0];
if (first instanceof Blob) {
return true;
}
}
} else if (input instanceof Blob) {
return true;
}
return false;
}
_isBatchInput(input) {
return input instanceof BatchUpload || input instanceof BatchBlob;
}
}
module.exports = Operation;