diff --git a/packages/nodes-base/nodes/Telegram/GenericFunctions.ts b/packages/nodes-base/nodes/Telegram/GenericFunctions.ts index ee6d9c47b6..f59c8826bc 100644 --- a/packages/nodes-base/nodes/Telegram/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Telegram/GenericFunctions.ts @@ -2,12 +2,16 @@ import { IExecuteFunctions, IHookFunctions, ILoadOptionsFunctions, + IWebhookFunctions, } from 'n8n-core'; -import { OptionsWithUri } from 'request'; -import { IDataObject } from 'n8n-workflow'; - +import { + OptionsWithUri, +} from 'request'; +import { + IDataObject, +} from 'n8n-workflow'; // Interface in n8n export interface IMarkupKeyboard { @@ -138,7 +142,7 @@ export function addAdditionalFields(this: IExecuteFunctions, body: IDataObject, * @param {object} body * @returns {Promise} */ -export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any +export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, endpoint: string, body: object, query?: IDataObject, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = this.getCredentials('telegramApi'); if (credentials === undefined) { @@ -157,9 +161,22 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa json: true, }; + if (Object.keys(option).length > 0) { + Object.assign(options, option); + } + + if (Object.keys(body).length === 0) { + delete options.body; + } + + if (Object.keys(query).length === 0) { + delete options.qs; + } + try { return await this.helpers.request!(options); } catch (error) { + if (error.statusCode === 401) { // Return a clear error throw new Error('The Telegram credentials are not valid!'); @@ -175,3 +192,16 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa throw error; } } + +export function getImageBySize(photos: IDataObject[], size: string): IDataObject | undefined { + + const sizes = { + 'small': 0, + 'medium': 1, + 'large': 2, + } as IDataObject; + + const index = sizes[size] as number; + + return photos[index]; +} diff --git a/packages/nodes-base/nodes/Telegram/IEvent.ts b/packages/nodes-base/nodes/Telegram/IEvent.ts new file mode 100644 index 0000000000..53f6f7e919 --- /dev/null +++ b/packages/nodes-base/nodes/Telegram/IEvent.ts @@ -0,0 +1,12 @@ +export interface IEvent { + message?: { + photo?: [ + { + file_id: string, + }, + ], + document?: { + file_id: string; + }, + }; +} diff --git a/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts b/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts index 30b2bc01d4..6472c8083c 100644 --- a/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts +++ b/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts @@ -4,15 +4,20 @@ import { } from 'n8n-core'; import { - INodeTypeDescription, + IDataObject, INodeType, + INodeTypeDescription, IWebhookResponseData, } from 'n8n-workflow'; import { apiRequest, + getImageBySize, } from './GenericFunctions'; +import { + IEvent, +} from './IEvent'; export class TelegramTrigger implements INodeType { description: INodeTypeDescription = { @@ -33,7 +38,7 @@ export class TelegramTrigger implements INodeType { { name: 'telegramApi', required: true, - } + }, ], webhooks: [ { @@ -105,6 +110,45 @@ export class TelegramTrigger implements INodeType { default: [], description: 'The update types to listen to.', }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + options: [ + { + displayName: 'Download Images/Files', + name: 'donwload', + type: 'boolean', + default: false, + description: `Telegram develiers the image in 3 sizes.
+ By default, just the larger image would be downloaded.
+ if you want to change the size set the field 'Image Size'`, + }, + { + displayName: 'Image Size', + name: 'imageSize', + type: 'options', + options: [ + { + name: 'Small', + value: 'small', + }, + { + name: 'Medium', + value: 'medium', + }, + { + name: 'Large', + value: 'large', + }, + ], + default: 'large', + description: 'The size of the image to be downloaded', + }, + ], + }, ], }; @@ -157,14 +201,74 @@ export class TelegramTrigger implements INodeType { }, }; - - async webhook(this: IWebhookFunctions): Promise { - const bodyData = this.getBodyData(); + + const credentials = this.getCredentials('telegramApi') as IDataObject; + + const bodyData = this.getBodyData() as IEvent; + + const additionalFields = this.getNodeParameter('additionalFields') as IDataObject; + + if (additionalFields.donwload === true) { + + let imageSize = 'large'; + + if ((bodyData.message && bodyData.message.photo && Array.isArray(bodyData.message.photo) || bodyData.message?.document)) { + + if (additionalFields.imageSize) { + + imageSize = additionalFields.imageSize as string; + + } + + let fileId; + + if (bodyData.message.photo) { + + let image = getImageBySize(bodyData.message.photo as IDataObject[], imageSize) as IDataObject; + + // When the image is sent from the desktop app telegram does not resize the image + // So return the only image avaiable + // Basically the Image Size parameter would work just when the images comes from the mobile app + if (image === undefined) { + image = bodyData.message.photo[0]; + } + + fileId = image.file_id; + + } else { + + fileId = bodyData.message?.document?.file_id; + } + + const { result: { file_path } } = await apiRequest.call(this, 'GET', `getFile?file_id=${fileId}`, {}); + + const file = await apiRequest.call(this, 'GET', '', {}, {}, { json: false, encoding: null, uri: `https://api.telegram.org/file/bot${credentials.accessToken}/${file_path}`, resolveWithFullResponse: true }); + + const data = Buffer.from(file.body as string); + + const fileName = file_path.split('/').pop(); + + const binaryData = await this.helpers.prepareBinaryData(data as unknown as Buffer, fileName); + + return { + workflowData: [ + [ + { + json: bodyData as unknown as IDataObject, + binary: { + data: binaryData, + }, + } + ] + ], + }; + } + } return { workflowData: [ - this.helpers.returnJsonArray([bodyData]) + this.helpers.returnJsonArray([bodyData as unknown as IDataObject]) ], }; }