feat(ServiceNow Node): Add attachment functionality (#3137)

*  Add ServiceNow attachment functionality

* 🔨 download fix

*  improvements

*  parameter name fix

*  download attachment for get all operation

*  filters update

*  hint update

*  Small improvements

Co-authored-by: Michael Kret <michael.k@radency.com>
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
This commit is contained in:
pemontto
2022-05-27 17:39:55 +01:00
committed by GitHub
parent b687ba11cc
commit c38f6af499
4 changed files with 464 additions and 2 deletions

View File

@@ -4,6 +4,7 @@ import {
} from 'n8n-core';
import {
IBinaryData,
IDataObject,
INodeExecutionData,
INodePropertyOptions,
@@ -16,10 +17,16 @@ import {
import {
mapEndpoint,
serviceNowApiRequest,
serviceNowDownloadAttachment,
serviceNowRequestAllItems,
sortData
} from './GenericFunctions';
import {
attachmentFields,
attachmentOperations,
} from './AttachmentDescription';
import {
businessServiceFields,
businessServiceOperations,
@@ -127,6 +134,10 @@ export class ServiceNow implements INodeType {
type: 'options',
noDataExpression: true,
options: [
{
name: 'Attachment',
value: 'attachment',
},
{
name: 'Business Service',
value: 'businessService',
@@ -166,7 +177,9 @@ export class ServiceNow implements INodeType {
],
default: 'user',
},
// ATTACHMENT SERVICE
...attachmentOperations,
...attachmentFields,
// BUSINESS SERVICE
...businessServiceOperations,
...businessServiceFields,
@@ -456,7 +469,117 @@ export class ServiceNow implements INodeType {
for (let i = 0; i < length; i++) {
try {
if (resource === 'businessService') {
// https://developer.servicenow.com/dev.do#!/reference/api/rome/rest/c_AttachmentAPI
if (resource === 'attachment') {
if (operation === 'get') {
const attachmentsSysId = this.getNodeParameter('attachmentId', i) as string;
const download = this.getNodeParameter('download', i) as boolean;
const endpoint = `/now/attachment/${attachmentsSysId}`;
const response = await serviceNowApiRequest.call(this, 'GET', endpoint, {});
const fileMetadata = response.result;
responseData = {
json: fileMetadata,
};
if (download) {
const outputField = this.getNodeParameter('outputField', i) as string;
responseData = {
...responseData,
binary: {
[outputField]: await serviceNowDownloadAttachment.call(
this,
endpoint,
fileMetadata.file_name,
fileMetadata.content_type,
),
},
};
}
} else if (operation === 'getAll') {
const download = this.getNodeParameter('download', i) as boolean;
const tableName = this.getNodeParameter('tableName', i) as string;
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
const options = this.getNodeParameter('options', i) as IDataObject;
qs = {} as IDataObject;
qs.sysparm_query = `table_name=${tableName}`;
if (options.queryFilter) {
qs.sysparm_query = `${qs.sysparm_query}^${options.queryFilter}`;
}
if (!returnAll) {
const limit = this.getNodeParameter('limit', i) as number;
qs.sysparm_limit = limit;
const response = await serviceNowApiRequest.call(this, 'GET', '/now/attachment', {}, qs);
responseData = response.result;
} else {
responseData = await serviceNowRequestAllItems.call(this, 'GET', '/now/attachment', {}, qs);
}
if (download) {
const outputField = this.getNodeParameter('outputField', i) as string;
const responseDataWithAttachments: IDataObject[] = [];
for (const data of responseData as IDataObject[]) {
responseDataWithAttachments.push({
json: data,
binary: {
[outputField]: await serviceNowDownloadAttachment.call(
this,
`/now/attachment/${data.sys_id}`,
data.file_name as string,
data.content_type as string,
),
},
});
}
responseData = responseDataWithAttachments;
} else {
responseData = (responseData as IDataObject[]).map( data => ({ json: data }));
}
} else if (operation === 'upload') {
const tableName = this.getNodeParameter('tableName', i) as string;
const recordId = this.getNodeParameter('id', i) as string;
const inputDataFieldName = this.getNodeParameter('inputDataFieldName', i) as string;
const options = this.getNodeParameter('options', i) as IDataObject;
let binaryData: IBinaryData;
if (items[i].binary && items[i].binary![inputDataFieldName]) {
binaryData = items[i].binary![inputDataFieldName];
} else {
throw new NodeOperationError(this.getNode(), `No binary data property "${inputDataFieldName}" does not exists on item!`);
}
const headers: IDataObject = {
'Content-Type': binaryData.mimeType,
};
const qs: IDataObject = {
table_name: tableName,
table_sys_id: recordId,
file_name: binaryData.fileName ? binaryData.fileName : `${inputDataFieldName}.${binaryData.fileExtension}`,
...options,
};
const body = await this.helpers.getBinaryDataBuffer(i, inputDataFieldName) as Buffer;
const response = await serviceNowApiRequest.call(this, 'POST', '/now/attachment/file', body, qs, '', {headers});
responseData = response.result;
} else if (operation === 'delete') {
const attachmentsSysId = this.getNodeParameter('attachmentId', i) as string;
await serviceNowApiRequest.call(this, 'DELETE', `/now/attachment/${attachmentsSysId}`);
responseData = {'success': true};
}
} else if (resource === 'businessService') {
if (operation === 'getAll') {
@@ -818,6 +941,12 @@ export class ServiceNow implements INodeType {
? returnData.push(...responseData)
: returnData.push(responseData);
}
if (resource === 'attachment') {
if (operation === 'get' || operation === 'getAll') {
return this.prepareOutputData(returnData as INodeExecutionData[]);
}
}
return [this.helpers.returnJsonArray(returnData)];
}
}