mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 04:34:06 -08:00
f63710a892
* feat: base structure for whatsapp node with credentials * feat: messages operation * feat: create generic api call with credentials and test first operation * fix: add missing template params * fix: language code for template * feat: media type and start of template components * fix: remove provider name from media type * lintfix * fix: format * feat: media operations w/o upload media type * ♻️ Convert WhatsApp Business node to declarative style * 🐛 form data not being sent with boundary in header * ✨ add media operations to WhatsApp * ✨ add credentials test to WhatsApp credentials * ♻️ move preview url to optional collection in whatsapp message * ♻️ renamed media operations in whatsapp node * :refactor: move media file name to optional fields in whatsapp node * ✨ add upload from n8n for whatsapp node message resource * 🔥 remove other template component types in whatsapp node * :speech_bubble: add specialised text for media types in WhatsApp node * ⚡ Load dinamically phone number and template name * ⚡ Add action property to all operations * 🔥 Remove unnecessary imports * ⚡ Use getBinaryDataBuffer helper * ⚡ Add components property * ✨ send components for whatsapp templates and template language * 🏷️ fix WhatsApp node message function types * 🏷️ fix any in whatsapp message functions * 🔥 remove unused import * ⚡ Improvements * ⚡ Add send location * ⚡ Add send contact * ⚡ Small improvement * ♻️ changes for review * 🐛 fix presend error * ♻️ change lat/long to numbers with proper clamping * fix: bad merge * refactor: changes for review * update package-lock.json * update package.-lock.json * update Co-authored-by: cxgarcia <schlaubitzcristobal@gmail.com> Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
1509 lines
30 KiB
TypeScript
1509 lines
30 KiB
TypeScript
import { INodeProperties } from 'n8n-workflow';
|
|
import {
|
|
cleanPhoneNumber,
|
|
componentsRequest,
|
|
mediaUploadFromItem,
|
|
sendErrorPostReceive,
|
|
setType,
|
|
templateInfo,
|
|
} from './MessageFunctions';
|
|
|
|
export const mediaTypes = ['image', 'video', 'audio', 'sticker', 'document'];
|
|
|
|
let currencies = require('currency-codes/data');
|
|
currencies = currencies.map(({ code, currency }: { code: string; currency: string }) => ({
|
|
name: `${code} - ${currency}`,
|
|
value: code,
|
|
}));
|
|
|
|
export const messageFields: INodeProperties[] = [
|
|
{
|
|
displayName: 'Operation',
|
|
noDataExpression: true,
|
|
name: 'operation',
|
|
type: 'options',
|
|
placeholder: '',
|
|
options: [
|
|
{
|
|
name: 'Send',
|
|
value: 'send',
|
|
action: 'Send message',
|
|
},
|
|
{
|
|
name: 'Send Template',
|
|
value: 'sendTemplate',
|
|
action: 'Send template',
|
|
},
|
|
],
|
|
default: 'sendTemplate',
|
|
routing: {
|
|
request: {
|
|
ignoreHttpStatusErrors: true,
|
|
},
|
|
send: {
|
|
preSend: [setType],
|
|
},
|
|
output: { postReceive: [sendErrorPostReceive] },
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
displayName: 'Messaging Product',
|
|
name: 'messagingProduct',
|
|
default: 'whatsapp',
|
|
type: 'hidden',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'messaging_product',
|
|
},
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Sender Phone Number (or ID)',
|
|
name: 'phoneNumberId',
|
|
type: 'options',
|
|
typeOptions: {
|
|
loadOptions: {
|
|
routing: {
|
|
request: {
|
|
url: '={{$credentials.businessAccountId}}/phone_numbers',
|
|
method: 'GET',
|
|
},
|
|
output: {
|
|
postReceive: [
|
|
{
|
|
type: 'rootProperty',
|
|
properties: {
|
|
property: 'data',
|
|
},
|
|
},
|
|
{
|
|
type: 'setKeyValue',
|
|
properties: {
|
|
name: '={{$responseItem.display_phone_number}} - {{$responseItem.verified_name}}',
|
|
value: '={{$responseItem.id}}',
|
|
},
|
|
},
|
|
{
|
|
type: 'sort',
|
|
properties: {
|
|
key: 'name',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
default: '',
|
|
placeholder: '',
|
|
required: true,
|
|
description:
|
|
"The ID of the business account's phone number from which the message will be sent from",
|
|
routing: {
|
|
request: {
|
|
method: 'POST',
|
|
url: '={{$value}}/messages',
|
|
},
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: "Recipient's Phone Number",
|
|
name: 'recipientPhoneNumber',
|
|
type: 'string',
|
|
default: '',
|
|
required: true,
|
|
description: 'Phone number of the recipient of the message',
|
|
hint: 'When entering a phone number, make sure to include the country code',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
preSend: [cleanPhoneNumber],
|
|
},
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'MessageType',
|
|
noDataExpression: true,
|
|
name: 'messageType',
|
|
type: 'options',
|
|
placeholder: '',
|
|
options: [
|
|
{
|
|
name: 'Audio',
|
|
value: 'audio',
|
|
},
|
|
{
|
|
name: 'Contacts',
|
|
value: 'contacts',
|
|
},
|
|
{
|
|
name: 'Document',
|
|
value: 'document',
|
|
},
|
|
{
|
|
name: 'Image',
|
|
value: 'image',
|
|
},
|
|
{
|
|
name: 'Location',
|
|
value: 'location',
|
|
},
|
|
{
|
|
name: 'Text',
|
|
value: 'text',
|
|
},
|
|
{
|
|
name: 'Video',
|
|
value: 'video',
|
|
},
|
|
],
|
|
default: 'text',
|
|
description: 'The type of the message',
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
operation: ['send'],
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
export const messageTypeFields: INodeProperties[] = [
|
|
// ----------------------------------
|
|
// type: contact
|
|
// ----------------------------------
|
|
{
|
|
displayName: 'Name',
|
|
name: 'name',
|
|
type: 'fixedCollection',
|
|
typeOptions: {
|
|
multipleValues: false,
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: ['contacts'],
|
|
},
|
|
},
|
|
placeholder: 'Add Parameter',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'Name',
|
|
name: 'data',
|
|
values: [
|
|
{
|
|
displayName: 'Formatted Name',
|
|
name: 'formatted_name',
|
|
type: 'string',
|
|
required: true,
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'contacts[0].name.formatted_name',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'First Name',
|
|
name: 'first_name',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'contacts[0].name.first_name',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Last Name',
|
|
name: 'last_name',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'contacts[0].name.last_name',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Middle Name',
|
|
name: 'middle_name',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'contacts[0].name.middle_name',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Suffix',
|
|
name: 'suffix',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'contacts[0].name.suffix',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Prefix',
|
|
name: 'prefix',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'contacts[0].name.prefix',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'Additional Fields',
|
|
name: 'additionalFields',
|
|
type: 'collection',
|
|
placeholder: 'Add Field',
|
|
default: {},
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: ['contacts'],
|
|
},
|
|
},
|
|
options: [
|
|
{
|
|
displayName: 'Addresses',
|
|
name: 'addresses',
|
|
type: 'fixedCollection',
|
|
typeOptions: {
|
|
multipleValues: true,
|
|
},
|
|
placeholder: 'Add Parameter',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'Address',
|
|
name: 'address',
|
|
values: [
|
|
{
|
|
displayName: 'Type',
|
|
name: 'type',
|
|
type: 'options',
|
|
options: [
|
|
{
|
|
name: 'Home',
|
|
value: 'HOME',
|
|
},
|
|
{
|
|
name: 'Work',
|
|
value: 'WORK',
|
|
},
|
|
],
|
|
default: 'HOME',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].addresses[{{$index}}].type',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Street',
|
|
name: 'street',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].addresses[{{$index}}].street',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'City',
|
|
name: 'city',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].addresses[{{$index}}].city',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'State',
|
|
name: 'state',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].addresses[{{$index}}].state',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Zip',
|
|
name: 'zip',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].addresses[{{$index}}].zip',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Country',
|
|
name: 'country',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].addresses[{{$index}}].country',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Country Code',
|
|
name: 'country_code',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].addresses[{{$index}}].country_code',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'Birthday',
|
|
name: 'birthday',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: 'contacts[0].birthday',
|
|
type: 'body',
|
|
},
|
|
},
|
|
placeholder: 'YYYY-MM-DD',
|
|
},
|
|
{
|
|
displayName: 'Emails',
|
|
name: 'emails',
|
|
type: 'fixedCollection',
|
|
typeOptions: {
|
|
multipleValues: true,
|
|
},
|
|
placeholder: 'Add Parameter',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'Email',
|
|
name: 'data',
|
|
values: [
|
|
{
|
|
displayName: 'Type',
|
|
name: 'type',
|
|
type: 'options',
|
|
options: [
|
|
{
|
|
name: 'Home',
|
|
value: 'HOME',
|
|
},
|
|
{
|
|
name: 'Work',
|
|
value: 'WORK',
|
|
},
|
|
],
|
|
default: 'HOME',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].emails[{{$index}}].type',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Email',
|
|
name: 'email',
|
|
type: 'string',
|
|
placeholder: 'name@email.com',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].emails[{{$index}}].email',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'Organization',
|
|
name: 'organization',
|
|
type: 'fixedCollection',
|
|
typeOptions: {
|
|
multipleValues: false,
|
|
},
|
|
placeholder: 'Add Parameter',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'Organization',
|
|
name: 'data',
|
|
values: [
|
|
{
|
|
displayName: 'Company',
|
|
name: 'company',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'contacts[0].org.company',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Department',
|
|
name: 'department',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'contacts[0].org.department',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Title',
|
|
name: 'title',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'contacts[0].org.title',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'Phones',
|
|
name: 'phones',
|
|
type: 'fixedCollection',
|
|
typeOptions: {
|
|
multipleValues: true,
|
|
},
|
|
placeholder: 'Add Parameter',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'Phone',
|
|
name: 'data',
|
|
values: [
|
|
{
|
|
displayName: 'Type',
|
|
name: 'type',
|
|
type: 'options',
|
|
options: [
|
|
{
|
|
name: 'Cell',
|
|
value: 'CELL',
|
|
},
|
|
{
|
|
name: 'Home',
|
|
value: 'HOME',
|
|
},
|
|
{
|
|
name: 'Iphone',
|
|
value: 'IPHONE',
|
|
},
|
|
{
|
|
name: 'Main',
|
|
value: 'MAIN',
|
|
},
|
|
{
|
|
name: 'WhatsApp ID',
|
|
value: 'wa_id',
|
|
},
|
|
{
|
|
name: 'Work',
|
|
value: 'WORK',
|
|
},
|
|
],
|
|
default: 'CELL',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].phones[{{$index}}].type',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Phone',
|
|
name: 'phone',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].phones[{{$index}}].phone',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'URLs',
|
|
name: 'urls',
|
|
type: 'fixedCollection',
|
|
typeOptions: {
|
|
multipleValues: true,
|
|
},
|
|
placeholder: 'Add Parameter',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'URL',
|
|
name: 'url',
|
|
values: [
|
|
{
|
|
displayName: 'Type',
|
|
name: 'type',
|
|
type: 'options',
|
|
options: [
|
|
{
|
|
name: 'Home',
|
|
value: 'HOME',
|
|
},
|
|
{
|
|
name: 'Work',
|
|
value: 'WORK',
|
|
},
|
|
],
|
|
default: 'HOME',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].urls[{{$index}}].type',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'URL',
|
|
name: 'url',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
property: '=contacts[0].urls[{{$index}}].url',
|
|
type: 'body',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
// ----------------------------------
|
|
// type: location
|
|
// ----------------------------------
|
|
{
|
|
displayName: 'Longitude',
|
|
name: 'longitude',
|
|
type: 'number',
|
|
required: true,
|
|
default: '',
|
|
typeOptions: {
|
|
minValue: -180,
|
|
maxValue: 180,
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
operation: ['send'],
|
|
messageType: ['location'],
|
|
},
|
|
},
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'location.longitude',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Latitude',
|
|
name: 'latitude',
|
|
type: 'number',
|
|
default: '',
|
|
required: true,
|
|
typeOptions: {
|
|
minValue: -90,
|
|
maxValue: 90,
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
operation: ['send'],
|
|
messageType: ['location'],
|
|
},
|
|
},
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'location.latitude',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Additional Fields',
|
|
name: 'additionalFields',
|
|
type: 'fixedCollection',
|
|
placeholder: 'Add Field',
|
|
default: {},
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
operation: ['send'],
|
|
messageType: ['location'],
|
|
},
|
|
},
|
|
options: [
|
|
{
|
|
displayName: 'Name and Address',
|
|
name: 'nameAndAddress',
|
|
values: [
|
|
{
|
|
displayName: 'Name',
|
|
name: 'name',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'location.name',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Address',
|
|
name: 'address',
|
|
type: 'string',
|
|
default: '',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'location.address',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
// ----------------------------------
|
|
// type: text
|
|
// ----------------------------------
|
|
{
|
|
displayName: 'Text Body',
|
|
name: 'textBody',
|
|
type: 'string',
|
|
required: true,
|
|
default: '',
|
|
description: 'The body of the message (max 4096 characters)',
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
operation: ['send'],
|
|
messageType: ['text'],
|
|
},
|
|
},
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'text.body',
|
|
},
|
|
},
|
|
},
|
|
// ----------------------------------
|
|
// type: media
|
|
// ----------------------------------
|
|
{
|
|
displayName: 'Take Audio From',
|
|
name: 'mediaPath',
|
|
type: 'options',
|
|
default: 'useMediaLink',
|
|
description: 'Use a link, an ID, or n8n to upload an audio file',
|
|
options: [
|
|
{
|
|
name: 'Link',
|
|
value: 'useMediaLink',
|
|
description:
|
|
'WhatsApp will download the audio, saving you the step of uploading audio yourself',
|
|
},
|
|
{
|
|
name: 'WhatsApp Media',
|
|
value: 'useMediaId',
|
|
description: 'If you have already uploaded the audio to WhatsApp',
|
|
},
|
|
{
|
|
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
|
name: 'n8n',
|
|
value: 'useMedian8n',
|
|
description: 'Use binary data passed into this node',
|
|
},
|
|
],
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: ['audio'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Take Document From',
|
|
name: 'mediaPath',
|
|
type: 'options',
|
|
default: 'useMediaLink',
|
|
description: 'Use a link, an ID, or n8n to upload a document',
|
|
options: [
|
|
{
|
|
name: 'Link',
|
|
value: 'useMediaLink',
|
|
description:
|
|
'When using a link, WhatsApp will download the document, saving you the step of uploading document yourself',
|
|
},
|
|
{
|
|
name: 'WhatsApp Media',
|
|
value: 'useMediaId',
|
|
description: 'You can use an ID if you have already uploaded the document to WhatsApp',
|
|
},
|
|
{
|
|
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
|
name: 'n8n',
|
|
value: 'useMedian8n',
|
|
description: 'Upload a binary file on the item being processed in n8n',
|
|
},
|
|
],
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: ['document'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Take Image From',
|
|
name: 'mediaPath',
|
|
type: 'options',
|
|
default: 'useMediaLink',
|
|
description: 'Use a link, an ID, or n8n to upload an image',
|
|
options: [
|
|
{
|
|
name: 'Link',
|
|
value: 'useMediaLink',
|
|
description:
|
|
'When using a link, WhatsApp will download the image, saving you the step of uploading image yourself',
|
|
},
|
|
{
|
|
name: 'WhatsApp Media',
|
|
value: 'useMediaId',
|
|
description: 'You can use an ID if you have already uploaded the image to WhatsApp',
|
|
},
|
|
{
|
|
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
|
name: 'n8n',
|
|
value: 'useMedian8n',
|
|
description: 'Upload a binary file on the item being processed in n8n',
|
|
},
|
|
],
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: ['image'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Take Video From',
|
|
name: 'mediaPath',
|
|
type: 'options',
|
|
default: 'useMediaLink',
|
|
description: 'Use a link, an ID, or n8n to upload a video',
|
|
options: [
|
|
{
|
|
name: 'Link',
|
|
value: 'useMediaLink',
|
|
description:
|
|
'When using a link, WhatsApp will download the video, saving you the step of uploading video yourself',
|
|
},
|
|
{
|
|
name: 'WhatsApp Media',
|
|
value: 'useMediaId',
|
|
description: 'You can use an ID if you have already uploaded the video to WhatsApp',
|
|
},
|
|
{
|
|
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
|
name: 'n8n',
|
|
value: 'useMedian8n',
|
|
description: 'Upload a binary file on the item being processed in n8n',
|
|
},
|
|
],
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: ['video'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Link',
|
|
name: 'mediaLink',
|
|
type: 'string',
|
|
default: '',
|
|
description: 'Link of the media to be sent',
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: mediaTypes,
|
|
mediaPath: ['useMediaLink'],
|
|
},
|
|
},
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: '={{$parameter["messageType"]}}.link',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'ID',
|
|
name: 'mediaId',
|
|
type: 'string',
|
|
default: '',
|
|
description: 'ID of the media to be sent',
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: mediaTypes,
|
|
mediaPath: ['useMediaId'],
|
|
},
|
|
},
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: '={{$parameter["messageType"]}}.id',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Input Data Field Name',
|
|
name: 'mediaPropertyName',
|
|
type: 'string',
|
|
default: 'data',
|
|
description: 'The name of the input field containing the binary file data to be uploaded',
|
|
required: true,
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: mediaTypes,
|
|
mediaPath: ['useMedian8n'],
|
|
},
|
|
},
|
|
routing: {
|
|
send: {
|
|
preSend: [mediaUploadFromItem],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Filename',
|
|
name: 'mediaFilename',
|
|
type: 'string',
|
|
default: '',
|
|
description: 'The name of the file (required when using a file ID)',
|
|
required: true,
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['send'],
|
|
messageType: ['document'],
|
|
mediaPath: ['useMediaId'],
|
|
},
|
|
},
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: '={{$parameter["messageType"]}}.filename',
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
displayName: 'Additional Fields',
|
|
name: 'additionalFields',
|
|
type: 'collection',
|
|
placeholder: 'Add Field',
|
|
default: {},
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
operation: ['send'],
|
|
messageType: mediaTypes,
|
|
},
|
|
},
|
|
options: [
|
|
{
|
|
displayName: 'Filename',
|
|
name: 'mediaFilename',
|
|
type: 'string',
|
|
default: '',
|
|
description: 'The name of the file',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: '={{$parameter["messageType"]}}.filename',
|
|
},
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
'/messageType': ['document'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Caption',
|
|
name: 'mediaCaption',
|
|
type: 'string',
|
|
default: '',
|
|
description: 'The caption of the media',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: '={{$parameter["messageType"]}}.caption',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
// ----------------------------------
|
|
// type: template
|
|
// ----------------------------------
|
|
{
|
|
displayName: 'Template',
|
|
name: 'template',
|
|
default: '',
|
|
type: 'options',
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['sendTemplate'],
|
|
resource: ['message'],
|
|
},
|
|
},
|
|
typeOptions: {
|
|
loadOptions: {
|
|
routing: {
|
|
request: {
|
|
url: '={{$credentials.businessAccountId}}/message_templates',
|
|
method: 'GET',
|
|
},
|
|
output: {
|
|
postReceive: [
|
|
{
|
|
type: 'rootProperty',
|
|
properties: {
|
|
property: 'data',
|
|
},
|
|
},
|
|
{
|
|
type: 'setKeyValue',
|
|
properties: {
|
|
name: '={{$responseItem.name}} - {{$responseItem.language}}',
|
|
value: '={{$responseItem.name}}|{{$responseItem.language}}',
|
|
},
|
|
},
|
|
{
|
|
type: 'sort',
|
|
properties: {
|
|
key: 'name',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
required: true,
|
|
description: 'Name of the template',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
// property: 'template.name',
|
|
preSend: [templateInfo],
|
|
},
|
|
},
|
|
},
|
|
//{
|
|
// // Search for ISO6391.getCode(language) in the Twitter node. Pehaps, we can use the same library?
|
|
// //TODO: would be nice to change this to a searchable dropdown with all the possible language codes
|
|
// displayName: 'Language Code',
|
|
// name: 'templateLanguageCode',
|
|
// type: 'string',
|
|
// default: 'en_US',
|
|
// displayOptions: {
|
|
// show: {
|
|
// operation: ['sendTemplate'],
|
|
// resource: ['message'],
|
|
// },
|
|
// },
|
|
// description:
|
|
// 'The code of the language or locale to use. Accepts both language and language_locale formats (e.g., en and en_US).',
|
|
// routing: {
|
|
// send: {
|
|
// type: 'body',
|
|
// property: 'template.language.code',
|
|
// },
|
|
// },
|
|
//},
|
|
{
|
|
displayName: 'Components',
|
|
name: 'components',
|
|
type: 'fixedCollection',
|
|
default: {},
|
|
typeOptions: {
|
|
multipleValues: true,
|
|
},
|
|
placeholder: 'Add Component',
|
|
displayOptions: {
|
|
show: {
|
|
operation: ['sendTemplate'],
|
|
resource: ['message'],
|
|
},
|
|
},
|
|
routing: {
|
|
send: {
|
|
preSend: [componentsRequest],
|
|
},
|
|
},
|
|
options: [
|
|
{
|
|
name: 'component',
|
|
displayName: 'Component',
|
|
values: [
|
|
{
|
|
displayName: 'Type',
|
|
name: 'type',
|
|
type: 'options',
|
|
options: [
|
|
{
|
|
name: 'Body',
|
|
value: 'body',
|
|
},
|
|
{
|
|
name: 'Button',
|
|
value: 'button',
|
|
},
|
|
{
|
|
name: 'Header',
|
|
value: 'header',
|
|
},
|
|
],
|
|
default: 'body',
|
|
},
|
|
{
|
|
displayName: 'Parameters',
|
|
name: 'bodyParameters',
|
|
type: 'fixedCollection',
|
|
typeOptions: {
|
|
sortable: true,
|
|
multipleValues: true,
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
type: ['body'],
|
|
},
|
|
},
|
|
placeholder: 'Add Parameter',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'Parameter',
|
|
name: 'parameter',
|
|
values: [
|
|
{
|
|
displayName: 'Type',
|
|
name: 'type',
|
|
type: 'options',
|
|
options: [
|
|
{
|
|
name: 'Text',
|
|
value: 'text',
|
|
},
|
|
{
|
|
name: 'Currency',
|
|
value: 'currency',
|
|
},
|
|
{
|
|
name: 'Date Time',
|
|
value: 'date_time',
|
|
},
|
|
],
|
|
default: 'text',
|
|
},
|
|
{
|
|
displayName: 'Text',
|
|
name: 'text',
|
|
type: 'string',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['text'],
|
|
},
|
|
},
|
|
default: '',
|
|
},
|
|
{
|
|
displayName: 'Currency Code',
|
|
name: 'code',
|
|
type: 'options',
|
|
options: currencies,
|
|
displayOptions: {
|
|
show: {
|
|
type: ['currency'],
|
|
},
|
|
},
|
|
default: '',
|
|
placeholder: 'USD',
|
|
},
|
|
{
|
|
displayName: 'Amount',
|
|
name: 'amount_1000',
|
|
type: 'number',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['currency'],
|
|
},
|
|
},
|
|
default: '',
|
|
placeholder: '',
|
|
},
|
|
{
|
|
displayName: 'Date Time',
|
|
name: 'date_time',
|
|
type: 'dateTime',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['date_time'],
|
|
},
|
|
},
|
|
default: '',
|
|
placeholder: '',
|
|
},
|
|
{
|
|
displayName: 'Fallback Value',
|
|
name: 'fallback_value',
|
|
type: 'string',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['currency'],
|
|
},
|
|
},
|
|
default: '',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'Sub Type',
|
|
name: 'sub_type',
|
|
type: 'options',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['button'],
|
|
},
|
|
},
|
|
options: [
|
|
{
|
|
name: 'Quick Reply',
|
|
value: 'quick_reply',
|
|
description: 'Allows your customer to call a phone number and visit a website',
|
|
},
|
|
{
|
|
name: 'URL',
|
|
value: 'url',
|
|
},
|
|
],
|
|
default: 'quick_reply',
|
|
},
|
|
{
|
|
displayName: 'Index',
|
|
name: 'index',
|
|
type: 'number',
|
|
typeOptions: {
|
|
maxValue: 2,
|
|
minValue: 0,
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
type: ['button'],
|
|
},
|
|
},
|
|
default: 0,
|
|
},
|
|
{
|
|
displayName: 'Parameters',
|
|
name: 'buttonParameters',
|
|
type: 'fixedCollection',
|
|
typeOptions: {
|
|
multipleValues: false,
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
type: ['button'],
|
|
},
|
|
},
|
|
placeholder: 'Add Parameter',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'Parameter',
|
|
name: 'parameter',
|
|
values: [
|
|
{
|
|
displayName: 'Type',
|
|
name: 'type',
|
|
type: 'options',
|
|
options: [
|
|
{
|
|
name: 'Payload',
|
|
value: 'payload',
|
|
},
|
|
{
|
|
name: 'Text',
|
|
value: 'text',
|
|
},
|
|
],
|
|
default: 'payload',
|
|
},
|
|
{
|
|
displayName: 'Payload',
|
|
name: 'payload',
|
|
type: 'string',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['payload'],
|
|
},
|
|
},
|
|
default: '',
|
|
},
|
|
{
|
|
displayName: 'Text',
|
|
name: 'text',
|
|
type: 'string',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['text'],
|
|
},
|
|
},
|
|
default: '',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'Parameters',
|
|
name: 'headerParameters',
|
|
type: 'fixedCollection',
|
|
typeOptions: {
|
|
sortable: true,
|
|
multipleValues: true,
|
|
},
|
|
displayOptions: {
|
|
show: {
|
|
type: ['header'],
|
|
},
|
|
},
|
|
placeholder: 'Add Parameter',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'Parameter',
|
|
name: 'parameter',
|
|
values: [
|
|
{
|
|
displayName: 'Type',
|
|
name: 'type',
|
|
type: 'options',
|
|
options: [
|
|
{
|
|
name: 'Text',
|
|
value: 'text',
|
|
},
|
|
{
|
|
name: 'Currency',
|
|
value: 'currency',
|
|
},
|
|
{
|
|
name: 'Date Time',
|
|
value: 'date_time',
|
|
},
|
|
{
|
|
name: 'Image',
|
|
value: 'image',
|
|
},
|
|
],
|
|
default: 'text',
|
|
},
|
|
{
|
|
displayName: 'Text',
|
|
name: 'text',
|
|
type: 'string',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['text'],
|
|
},
|
|
},
|
|
default: '',
|
|
},
|
|
{
|
|
displayName: 'Currency Code',
|
|
name: 'code',
|
|
type: 'options',
|
|
options: currencies,
|
|
displayOptions: {
|
|
show: {
|
|
type: ['currency'],
|
|
},
|
|
},
|
|
default: '',
|
|
placeholder: 'USD',
|
|
},
|
|
{
|
|
displayName: 'Amount',
|
|
name: 'amount_1000',
|
|
type: 'number',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['currency'],
|
|
},
|
|
},
|
|
default: '',
|
|
placeholder: '',
|
|
},
|
|
{
|
|
displayName: 'Date Time',
|
|
name: 'date_time',
|
|
type: 'dateTime',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['date_time'],
|
|
},
|
|
},
|
|
default: '',
|
|
placeholder: '',
|
|
},
|
|
{
|
|
displayName: 'Image Link',
|
|
name: 'imageLink',
|
|
type: 'string',
|
|
displayOptions: {
|
|
show: {
|
|
type: ['image'],
|
|
},
|
|
},
|
|
default: '',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'Additional Fields',
|
|
name: 'additionalFields',
|
|
type: 'collection',
|
|
placeholder: 'Add Field',
|
|
default: {},
|
|
displayOptions: {
|
|
show: {
|
|
resource: ['message'],
|
|
operation: ['send'],
|
|
messageType: ['text'],
|
|
},
|
|
},
|
|
options: [
|
|
{
|
|
displayName: 'Show URL Previews',
|
|
name: 'previewUrl',
|
|
type: 'boolean',
|
|
default: false,
|
|
description: 'Whether to display URL previews in text messages',
|
|
routing: {
|
|
send: {
|
|
type: 'body',
|
|
property: 'text.preview_url',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
];
|