feat(Slack Node): Update to use the new API method for file uploads (#9323)

This commit is contained in:
Jon 2024-05-08 10:40:24 +01:00 committed by GitHub
parent 435272b568
commit 695e762663
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 120 additions and 24 deletions

View file

@ -14,13 +14,14 @@ export class Slack extends VersionedNodeType {
group: ['output'], group: ['output'],
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Slack API', description: 'Consume Slack API',
defaultVersion: 2.1, defaultVersion: 2.2,
}; };
const nodeVersions: IVersionedNodeType['nodeVersions'] = { const nodeVersions: IVersionedNodeType['nodeVersions'] = {
1: new SlackV1(baseDescription), 1: new SlackV1(baseDescription),
2: new SlackV2(baseDescription), 2: new SlackV2(baseDescription),
2.1: new SlackV2(baseDescription), 2.1: new SlackV2(baseDescription),
2.2: new SlackV2(baseDescription),
}; };
super(nodeVersions, baseDescription); super(nodeVersions, baseDescription);

View file

@ -47,6 +47,7 @@ export const fileFields: INodeProperties[] = [
show: { show: {
operation: ['upload'], operation: ['upload'],
resource: ['file'], resource: ['file'],
'@version': [2, 2.1],
}, },
}, },
description: 'Whether the data to upload should be taken from binary field', description: 'Whether the data to upload should be taken from binary field',
@ -61,6 +62,7 @@ export const fileFields: INodeProperties[] = [
operation: ['upload'], operation: ['upload'],
resource: ['file'], resource: ['file'],
binaryData: [false], binaryData: [false],
'@version': [2, 2.1],
}, },
}, },
placeholder: '', placeholder: '',
@ -76,6 +78,23 @@ export const fileFields: INodeProperties[] = [
operation: ['upload'], operation: ['upload'],
resource: ['file'], resource: ['file'],
binaryData: [true], binaryData: [true],
'@version': [2, 2.1],
},
},
placeholder: '',
description: 'Name of the binary property which contains the data for the file to be uploaded',
},
{
displayName: 'File Property',
name: 'binaryPropertyName',
type: 'string',
default: 'data',
required: true,
displayOptions: {
show: {
operation: ['upload'],
resource: ['file'],
'@version': [2.2],
}, },
}, },
placeholder: '', placeholder: '',
@ -102,10 +121,31 @@ export const fileFields: INodeProperties[] = [
typeOptions: { typeOptions: {
loadOptionsMethod: 'getChannels', loadOptionsMethod: 'getChannels',
}, },
displayOptions: {
show: {
'@version': [2, 2.1],
},
},
default: [], default: [],
description: description:
'The channels to send the file to. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', 'The channels to send the file to. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{
displayName: 'Channel Name or ID',
name: 'channelId',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getChannels',
},
displayOptions: {
show: {
'@version': [2.2],
},
},
default: [],
description:
'The channel to send the file to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{ {
displayName: 'File Name', displayName: 'File Name',
name: 'fileName', name: 'fileName',

View file

@ -29,7 +29,7 @@ export async function slackApiRequest(
}, },
body, body,
qs: query, qs: query,
uri: `https://slack.com/api${resource}`, uri: resource.startsWith('https') ? resource : `https://slack.com/api${resource}`,
json: true, json: true,
}; };
options = Object.assign({}, options, option); options = Object.assign({}, options, option);
@ -78,6 +78,7 @@ export async function slackApiRequest(
}, },
); );
} }
throw new NodeOperationError( throw new NodeOperationError(
this.getNode(), this.getNode(),
'Slack error response: ' + JSON.stringify(response.error), 'Slack error response: ' + JSON.stringify(response.error),

View file

@ -38,7 +38,7 @@ export class SlackV2 implements INodeType {
constructor(baseDescription: INodeTypeBaseDescription) { constructor(baseDescription: INodeTypeBaseDescription) {
this.description = { this.description = {
...baseDescription, ...baseDescription,
version: [2, 2.1], version: [2, 2.1, 2.2],
defaults: { defaults: {
name: 'Slack', name: 'Slack',
}, },
@ -1040,11 +1040,13 @@ export class SlackV2 implements INodeType {
if (operation === 'upload') { if (operation === 'upload') {
const options = this.getNodeParameter('options', i); const options = this.getNodeParameter('options', i);
const body: IDataObject = {}; const body: IDataObject = {};
const fileBody: IDataObject = {};
if (options.channelIds) { if (options.channelIds) {
body.channels = (options.channelIds as string[]).join(','); body.channels = (options.channelIds as string[]).join(',');
} }
if (options.fileName) { if (options.channelId) {
body.filename = options.fileName as string; body.channel_id = options.channelId as string;
} }
if (options.initialComment) { if (options.initialComment) {
body.initial_comment = options.initialComment as string; body.initial_comment = options.initialComment as string;
@ -1053,18 +1055,27 @@ export class SlackV2 implements INodeType {
body.thread_ts = options.threadTs as string; body.thread_ts = options.threadTs as string;
} }
if (options.title) { if (options.title) {
if (nodeVersion <= 2.1) {
body.title = options.title as string; body.title = options.title as string;
} }
if (this.getNodeParameter('binaryData', i)) { }
if (this.getNodeParameter('binaryData', i, false) || nodeVersion > 2.1) {
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i); const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName); const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
let fileSize: number;
let uploadData: Buffer | Readable; let uploadData: Buffer | Readable;
if (binaryData.id) { if (binaryData.id) {
uploadData = await this.helpers.getBinaryStream(binaryData.id); uploadData = await this.helpers.getBinaryStream(binaryData.id);
const metadata = await this.helpers.getBinaryMetadata(binaryData.id);
fileSize = metadata.fileSize;
} else { } else {
uploadData = Buffer.from(binaryData.data, BINARY_ENCODING); uploadData = Buffer.from(binaryData.data, BINARY_ENCODING);
fileSize = uploadData.length;
} }
if (nodeVersion <= 2.1) {
body.file = { body.file = {
value: uploadData, value: uploadData,
options: { options: {
@ -1072,6 +1083,7 @@ export class SlackV2 implements INodeType {
contentType: binaryData.mimeType, contentType: binaryData.mimeType,
}, },
}; };
responseData = await slackApiRequest.call( responseData = await slackApiRequest.call(
this, this,
'POST', 'POST',
@ -1082,6 +1094,48 @@ export class SlackV2 implements INodeType {
{ formData: body }, { formData: body },
); );
responseData = responseData.file; responseData = responseData.file;
} else {
fileBody.file = {
value: uploadData,
options: {
filename: binaryData.fileName,
contentType: binaryData.mimeType,
},
};
const uploadUrl = await slackApiRequest.call(
this,
'GET',
'/files.getUploadURLExternal',
{},
{
filename: options.fileName ? options.fileName : binaryData.fileName,
length: fileSize,
},
);
await slackApiRequest.call(
this,
'POST',
uploadUrl.upload_url,
{},
qs,
{ 'Content-Type': 'multipart/form-data' },
{ formData: fileBody },
);
body.files = [
{
id: uploadUrl.file_id,
title: options.title ? options.title : binaryData.fileName,
},
];
responseData = await slackApiRequest.call(
this,
'POST',
'/files.completeUploadExternal',
body,
);
responseData = responseData.files;
}
} else { } else {
const fileContent = this.getNodeParameter('fileContent', i) as string; const fileContent = this.getNodeParameter('fileContent', i) as string;
body.content = fileContent; body.content = fileContent;