From edc6651a9b0e79173f3fcf5a1cb3ae5311aa4834 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Fri, 8 Nov 2019 23:11:01 -0500 Subject: [PATCH 1/5] rocketchat-node-setup --- .../credentials/RocketchatApi.credentials.ts | 18 ++++++ .../nodes/Rocketchat/GenericFunctions.ts | 51 +++++++++++++++++ .../nodes/Rocketchat/Rocketchat.node.ts | 53 ++++++++++++++++++ .../nodes/Rocketchat/rocketchat.png | Bin 0 -> 5747 bytes packages/nodes-base/package.json | 6 +- 5 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 packages/nodes-base/credentials/RocketchatApi.credentials.ts create mode 100644 packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts create mode 100644 packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts create mode 100644 packages/nodes-base/nodes/Rocketchat/rocketchat.png diff --git a/packages/nodes-base/credentials/RocketchatApi.credentials.ts b/packages/nodes-base/credentials/RocketchatApi.credentials.ts new file mode 100644 index 0000000000..ab6d0019ed --- /dev/null +++ b/packages/nodes-base/credentials/RocketchatApi.credentials.ts @@ -0,0 +1,18 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + + +export class RocketchatApi implements ICredentialType { + name = 'rocketchatApi'; + displayName = 'Rocket API'; + properties = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts new file mode 100644 index 0000000000..1e00514fc7 --- /dev/null +++ b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts @@ -0,0 +1,51 @@ +import { OptionsWithUri } from 'request'; + +import { + IExecuteFunctions, + IHookFunctions, + ILoadOptionsFunctions, + IExecuteSingleFunctions, + BINARY_ENCODING +} from 'n8n-core'; + +import * as _ from 'lodash'; + +export async function rocketchatApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, resource: string, method: string, body: any = {}, headers?: object): Promise { // tslint:disable-line:no-any + + const credentials = this.getCredentials('rocketchatApi'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + const apiKey = `${credentials.apiKey}:X`; + + const headerWithAuthentication = Object.assign({}, headers, { Authorization: `${Buffer.from(apiKey).toString(BINARY_ENCODING)}` }); + + const endpoint = ''; + + const options: OptionsWithUri = { + headers: headerWithAuthentication, + method, + body, + uri: `https://${credentials.domain}.${endpoint}${resource}`, + json: true + }; + + if (_.isEmpty(options.body)) { + delete options.body; + } + + try { + return await this.helpers.request!(options); + } catch (error) { + console.error(error); + + const errorMessage = error.response.body.message || error.response.body.Message; + + if (errorMessage !== undefined) { + throw errorMessage; + } + throw error.response.body; + } +} diff --git a/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts new file mode 100644 index 0000000000..1a2ff65341 --- /dev/null +++ b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts @@ -0,0 +1,53 @@ +import { + IExecuteSingleFunctions, +} from 'n8n-core'; +import { + IDataObject, + INodeTypeDescription, + INodeExecutionData, + INodeType, + ILoadOptionsFunctions, + INodePropertyOptions, +} from 'n8n-workflow'; +import { + rocketchatApiRequest +} from './GenericFunctions'; + + +export class Rocketchat implements INodeType { + + description: INodeTypeDescription = { + displayName: 'Rocketchat', + name: 'Rocketchat', + icon: 'file:Rocketchat.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume Rocketchat API', + defaults: { + name: 'Rocketchat', + color: '#c02428', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'rocketchatApi', + required: true, + } + ], + properties: [ + + ] + }; + + methods = { + + }; + + async executeSingle(this: IExecuteSingleFunctions): Promise { + return { + json: {} + }; + } +} diff --git a/packages/nodes-base/nodes/Rocketchat/rocketchat.png b/packages/nodes-base/nodes/Rocketchat/rocketchat.png new file mode 100644 index 0000000000000000000000000000000000000000..93dfcacf17fb871a068195cc057ae93aa56fe6b3 GIT binary patch literal 5747 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 Date: Sat, 9 Nov 2019 11:57:22 -0500 Subject: [PATCH 2/5] UI finished --- .../nodes/Freshdesk/Freshdesk.node.ts | 784 ------------------ .../nodes/Rocketchat/Rocketchat.node.ts | 270 +++++- .../nodes/Rocketchat/rocketchat.png | Bin 5747 -> 4226 bytes 3 files changed, 267 insertions(+), 787 deletions(-) delete mode 100644 packages/nodes-base/nodes/Freshdesk/Freshdesk.node.ts diff --git a/packages/nodes-base/nodes/Freshdesk/Freshdesk.node.ts b/packages/nodes-base/nodes/Freshdesk/Freshdesk.node.ts deleted file mode 100644 index 3fb530faa4..0000000000 --- a/packages/nodes-base/nodes/Freshdesk/Freshdesk.node.ts +++ /dev/null @@ -1,784 +0,0 @@ -import { - IExecuteSingleFunctions, -} from 'n8n-core'; -import { - IDataObject, - INodeTypeDescription, - INodeExecutionData, - INodeType, - ILoadOptionsFunctions, - INodePropertyOptions, -} from 'n8n-workflow'; -import { - freshdeskApiRequest, - validateJSON, - capitalize -} from './GenericFunctions'; - -enum Status { - Open = 1, - Pending = 2, - Resolved = 3, - Closed = 4 -} - -enum Priority { - Low = 1, - Medium = 2, - High = 3, - Urgent = 4 -} - -enum Source { - Email = 1, - Portal = 2, - Phone = 3, - Chat = 4, - Mobihelp = 5, - FeedbackWidget = 6, - OutboundEmail = 7 -} - -interface ICreateTicketBody { - name?: string; - requester_id?: number; - email?: string; - facebook_id?: string; - phone?: string; - twitter_id?: string; - unique_external_id?: string; - subject?: string | null; - type?: string; - status: Status; - priority: Priority; - description?: string; - responder_id?: number; - cc_emails?: [string]; - custom_fields?: IDataObject; - due_by?: string; - email_config_id?: number; - fr_due_by?: string; - group_id?: number; - product_id?: number; - source: Source; - tags?: [string]; - company_id?: number; -} - -export class Freshdesk implements INodeType { - - description: INodeTypeDescription = { - displayName: 'Freshdesk', - name: 'freshdesk', - icon: 'file:freshdesk.png', - group: ['output'], - version: 1, - subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', - description: 'Consume Freshdesk API', - defaults: { - name: 'Freshdesk', - color: '#c02428', - }, - inputs: ['main'], - outputs: ['main'], - credentials: [ - { - name: 'freshdeskApi', - required: true, - } - ], - properties: [ - { - displayName: 'Resource', - name: 'resource', - type: 'options', - required: true, - options: [ - { - name: 'Ticket', - value: 'ticket', - }, - ], - default: 'ticket', - description: 'The resource to operate on.', - }, - { - displayName: 'Operation', - name: 'operation', - type: 'options', - required: true, - displayOptions: { - show: { - resource: [ - 'ticket', - ] - }, - }, - options: [ - { - name: 'Create', - value: 'create', - description: 'Create a new ticket', - } - ], - default: 'create', - description: 'The operation to perform.', - }, - { - displayName: 'Requester Identification', - name: 'requester', - type: 'options', - required: true, - displayOptions: { - show: { - resource: [ - 'ticket', - ], - operation: [ - 'create' - ] - }, - }, - options: [ - { - name: 'Requester Id', - value: 'requesterId', - description: `User ID of the requester. For existing contacts, the requester_id can be passed instead of the requester's email.`, - }, - { - name: 'Email', - value: 'email', - description: `Email address of the requester. If no contact exists with this email address in Freshdesk, it will be added as a new contact.`, - }, - { - name: 'Facebook Id', - value: 'facebookId', - description: `Facebook ID of the requester. If no contact exists with this facebook_id, then a new contact will be created.`, - }, - { - name: 'Phone', - value: 'phone', - description: `Phone number of the requester. If no contact exists with this phone number in Freshdesk, it will be added as a new contact. If the phone number is set and the email address is not, then the name attribute is mandatory.`, - }, - { - name: 'Twitter Id', - value: 'twitterId', - description: `Twitter handle of the requester. If no contact exists with this handle in Freshdesk, it will be added as a new contact.`, - }, - { - name: 'Unique External Id', - value: 'uniqueExternalId', - description: `External ID of the requester. If no contact exists with this external ID in Freshdesk, they will be added as a new contact.`, - }, - ], - default: 'requesterId', - description: 'Requester Identification', - }, - { - displayName: 'Value', - name: 'requesterIdentificationValue', - type: 'string', - required: true, - displayOptions: { - show: { - resource: [ - 'ticket', - ], - operation: [ - 'create' - ] - }, - }, - default: '', - description: `Value of the identification selected `, - }, - { - displayName: 'Status', - name: 'status', - type: 'options', - required: true, - displayOptions: { - show: { - resource: [ - 'ticket', - ], - operation: [ - 'create' - ] - }, - }, - options: [ - { - name: 'Open', - value: 'open', - }, - { - name: 'Pending', - value: 'pending', - }, - { - name: 'Resolved', - value: 'resolved', - }, - { - name: 'Closed', - value: 'closed', - } - ], - default: 'pending', - description: 'Status', - }, - { - displayName: 'Priority', - name: 'priority', - type: 'options', - required: true, - displayOptions: { - show: { - resource: [ - 'ticket', - ], - operation: [ - 'create' - ] - }, - }, - options: [ - { - name: 'Low', - value: 'low', - }, - { - name: 'Medium', - value: 'medium', - }, - { - name: 'High', - value: 'high', - }, - { - name: 'Urgent', - value: 'urgent', - } - ], - default: 'low', - description: 'Priority', - }, - { - displayName: 'Source', - name: 'source', - type: 'options', - required: true, - displayOptions: { - show: { - resource: [ - 'ticket', - ], - operation: [ - 'create' - ] - }, - }, - options: [ - { - name: 'Email', - value: 'email', - }, - { - name: 'Portal', - value: 'portal', - }, - { - name: 'Phone', - value: 'phone', - }, - { - name: 'Chat', - value: 'chat', - }, - { - name: 'Mobihelp', - value: 'mobileHelp', - }, - { - name: 'Feedback Widget', - value: 'feedbackWidget', - }, - { - name: 'Outbound Email', - value: 'OutboundEmail', - } - ], - default: 'portal', - description: 'The channel through which the ticket was created.', - }, - // { - // displayName: 'JSON Parameters', - // name: 'jsonParameters', - // type: 'boolean', - // default: false, - // description: '', - // displayOptions: { - // show: { - // resource: [ - // 'ticket' - // ], - // operation: [ - // 'create', - // ] - // }, - // }, - // }, - { - displayName: 'Options', - name: 'options', - type: 'collection', - placeholder: 'Add Option', - default: {}, - displayOptions: { - show: { - resource: [ - 'ticket' - ], - operation: [ - 'create' - ], - }, - }, - options: [ - { - displayName: 'Name', - name: 'name', - type: 'string', - default: '', - placeholder: '', - description: 'Name of the requester', - }, - { - displayName: 'Subject', - name: 'subject', - type: 'string', - default: '', - placeholder: '', - description: 'Subject of the ticket.', - }, - { - displayName: 'Type', - name: 'type', - type: 'options', - default: 'Question', - description: 'Helps categorize the ticket according to the different kinds of issues your support team deals with.', - options: [ - { - name: 'Question', - value: 'Question' - }, - { - name: 'Incident', - value: 'Incident' - }, - { - name: 'Problem', - value: 'Problem' - }, - { - name: 'Feature Request', - value: 'Feature Request' - }, - { - name: 'Refund', - value: 'Refund' - }, - ] - }, - { - displayName: 'Description', - name: 'description', - type: 'string', - required: false, - default: '', - typeOptions: { - rows: 5, - alwaysOpenEditWindow: true, - }, - description: 'HTML content of the ticket.', - }, - { - displayName: 'Agent', - name: 'agent', - type: 'options', - required: false, - default: '', - typeOptions: { - loadOptionsMethod: 'getAgents' - }, - description: 'ID of the agent to whom the ticket has been assigned', - }, - { - displayName: 'CC Emails', - name: 'ccEmails', - required: false, - type: 'string', - default: '', - description: `separated by , email addresses added in the 'cc' field of the incoming ticket email`, - }, - { - displayName: 'Tags', - name: 'tags', - required: false, - type: 'string', - default: '', - description: `separated by , tags that have been associated with the ticket`, - }, - { - displayName: 'Due By', - name: 'dueBy', - required: false, - type: 'dateTime', - default: '', - description: `Timestamp that denotes when the ticket is due to be resolved`, - }, - { - displayName: 'Email config Id', - name: 'emailConfigId', - type: 'number', - required: false, - default: '', - description: `ID of email config which is used for this ticket. (i.e., support@yourcompany.com/sales@yourcompany.com) - If product_id is given and email_config_id is not given, product's primary email_config_id will be set`, - }, - { - displayName: 'FR Due By', - name: 'frDueBy', - type: 'dateTime', - required: false, - default: '', - description: `Timestamp that denotes when the first response is due`, - }, - { - displayName: 'Group', - name: 'group', - required: false, - type: 'options', - default: '', - typeOptions: { - loadOptionsMethod: 'getGroups' - }, - description: `ID of the group to which the ticket has been assigned. The default value is the ID of the group that is associated with the given email_config_id`, - }, - { - displayName: 'Product', - name: 'product', - required: false, - type: 'options', - default: '', - typeOptions: { - loadOptionsMethod: 'getProducts' - }, - description: `ID of the product to which the ticket is associated. - It will be ignored if the email_config_id attribute is set in the request.`, - }, - { - displayName: 'Company', - name: 'company', - required: false, - type: 'options', - default: '', - typeOptions: { - loadOptionsMethod: 'getCompanies' - }, - description: `Company ID of the requester. This attribute can only be set if the Multiple Companies feature is enabled (Estate plan and above)`, - }, - ] - }, - // { - // displayName: 'Custom Fields', - // name: 'customFieldsUi', - // placeholder: 'Add Custom fields', - // type: 'fixedCollection', - // required: false, - // default: '', - // typeOptions: { - // multipleValues: true, - // }, - // displayOptions: { - // show: { - // resource: [ - // 'ticket' - // ], - // operation: [ - // 'create' - // ], - // jsonParameters: [ - // false, - // ], - // }, - // }, - // description: 'Key value pairs containing the names and values of custom fields.', - // options: [ - // { - // name: 'customFieldsValues', - // displayName: 'Custom fields', - // values: [ - // { - // displayName: 'Key', - // required: false, - // name: 'key', - // type: 'string', - // default: '', - // }, - // { - // displayName: 'Value', - // name: 'value', - // type: 'string', - // required: false, - // default: '', - // }, - // ], - // }, - // ], - // }, - // { - // displayName: 'Custom Fields', - // name: 'customFieldsJson', - // type: 'json', - // typeOptions: { - // alwaysOpenEditWindow: true, - // }, - // displayOptions: { - // show: { - // resource: [ - // 'ticket' - // ], - // operation: [ - // 'create' - // ], - // jsonParameters: [ - // true, - // ], - // }, - // }, - // default: '', - // required: false, - // placeholder: `{ - // "gadget":"Cold Welder" - // }`, - // description: 'Key value pairs containing the names and values of custom fields.', - // }, - ] - }; - - methods = { - loadOptions: { - // Get all the agents to display them to user so that he can - // select them easily - async getAgents(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; - let agents; - try { - agents = await freshdeskApiRequest.call(this, '/agents', 'GET'); - } catch (err) { - throw new Error(`Freshdesk Error: ${err}`); - } - for (const agent of agents) { - const agentName = agent.contact.name; - const agentId = agent.id; - - returnData.push({ - name: agentName, - value: agentId, - }); - } - return returnData; - }, - - // Get all the groups to display them to user so that he can - // select them easily - async getGroups(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; - let groups; - try { - groups = await freshdeskApiRequest.call(this, '/groups', 'GET'); - } catch (err) { - throw new Error(`Freshdesk Error: ${err}`); - } - for (const group of groups) { - const groupName = group.name; - const groupId = group.id; - - returnData.push({ - name: groupName, - value: groupId, - }); - } - return returnData; - }, - - // Get all the products to display them to user so that he can - // select them easily - async getProducts(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; - let products; - try { - products = await freshdeskApiRequest.call(this, '/products', 'GET'); - } catch (err) { - throw new Error(`Freshdesk Error: ${err}`); - } - for (const product of products) { - const productName = product.name; - const productId = product.id; - - returnData.push({ - name: productName, - value: productId, - }); - } - return returnData; - }, - - // Get all the companies to display them to user so that he can - // select them easily - async getCompanies(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; - let companies; - try { - companies = await freshdeskApiRequest.call(this, '/companies', 'GET'); - } catch (err) { - throw new Error(`Freshdesk Error: ${err}`); - } - for (const company of companies) { - const companyName = company.name; - const companyId = company.id; - - returnData.push({ - name: companyName, - value: companyId, - }); - } - return returnData; - }, - }, - }; - - async executeSingle(this: IExecuteSingleFunctions): Promise { - const resource = this.getNodeParameter('resource') as string; - const opeation = this.getNodeParameter('operation') as string; - let response; - - if (resource === 'ticket') { - if (opeation === 'create') { - const requester = this.getNodeParameter('requester') as string; - const value = this.getNodeParameter('requesterIdentificationValue') as string; - const status = this.getNodeParameter('status') as string; - const priority = this.getNodeParameter('priority') as string; - const source = this.getNodeParameter('source') as string; - const options = this.getNodeParameter('options') as IDataObject; - //const jsonActive = this.getNodeParameter('jsonParameters') as boolean; - - const body: ICreateTicketBody = { - // @ts-ignore - status: Status[capitalize(status)], - // @ts-ignore - priority: Priority[capitalize(priority)], - // @ts-ignore - source: Source[capitalize(source)] - }; - - if (requester === 'requesterId') { - // @ts-ignore - if (isNaN(value)) { - throw new Error('Requester Id must be a number'); - } - body.requester_id = parseInt(value, 10); - } else if (requester === 'email'){ - body.email = value; - } else if (requester === 'facebookId'){ - body.facebook_id = value; - } else if (requester === 'phone'){ - body.phone = value; - } else if (requester === 'twitterId'){ - body.twitter_id = value; - } else if (requester === 'uniqueExternalId'){ - body.unique_external_id = value; - } - - // if (!jsonActive) { - // const customFieldsUi = this.getNodeParameter('customFieldsUi') as IDataObject; - // if (Object.keys(customFieldsUi).length > 0) { - // const aux: IDataObject = {}; - // // @ts-ignore - // customFieldsUi.customFieldsValues.forEach( o => { - // aux[`${o.key}`] = o.value; - // return aux; - // }); - // body.custom_fields = aux; - // } else { - // body.custom_fields = validateJSON(this.getNodeParameter('customFielsJson') as string); - // } - - if (options.name) { - body.name = options.name as string; - } - - if (options.subject) { - body.subject = options.subject as string; - } else { - body.subject = 'null'; - } - - if (options.type) { - body.type = options.type as string; - } - - if (options.description) { - body.description = options.description as string; - } else { - body.description = 'null'; - } - - if (options.agent) { - options.responder_id = options.agent as number; - } - - if (options.company) { - options.company_id = options.company as number; - } - - if (options.product) { - options.product_id = options.product as number; - } - - if (options.group) { - options.group_id = options.group as number; - } - - if (options.frDueBy) { - options.fr_due_by = options.frDueBy as string; - } - - if (options.emailConfigId) { - options.email_config_id = options.emailConfigId as number; - } - - if (options.dueBy) { - options.due_by = options.dueBy as string; - } - - if (options.ccEmails) { - // @ts-ignore - options.cc_emails = options.ccEmails.split(',') as [string]; - } - - try { - response = await freshdeskApiRequest.call(this, '/tickets', 'POST', body); - } catch (err) { - throw new Error(`Freskdesk Error: ${JSON.stringify(err)}`); - } - } - } - - return { - json: response - }; - } -} diff --git a/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts index 1a2ff65341..a0e5d2f4f4 100644 --- a/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts +++ b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts @@ -19,10 +19,10 @@ export class Rocketchat implements INodeType { description: INodeTypeDescription = { displayName: 'Rocketchat', name: 'Rocketchat', - icon: 'file:Rocketchat.png', + icon: 'file:rocketchat.png', group: ['output'], version: 1, - subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}', description: 'Consume Rocketchat API', defaults: { name: 'Rocketchat', @@ -37,7 +37,271 @@ export class Rocketchat implements INodeType { } ], properties: [ - + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Chat', + value: 'chat', + }, + ], + default: '', + description: 'The resource to operate on.', + }, + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'chat', + ], + }, + }, + options: [ + { + name: 'Post Message', + value: 'postMessage', + description: 'Post a message to a channel or a direct message', + }, + ], + default: '', + description: 'The operation to perform.', + }, + { + displayName: 'Alias', + name: 'alias', + type: 'string', + displayOptions: { + show: { + resource: [ + 'chat', + ], + operation: [ + 'postMessage' + ] + }, + }, + default: '', + description: 'This will cause the message’s name to appear as the given alias, but your username will still display.', + }, + { + displayName: 'Avatar', + name: 'avatar', + type: 'string', + displayOptions: { + show: { + resource: [ + 'chat', + ], + operation: [ + 'postMessage' + ] + }, + }, + default: '', + description: 'If provided, this will make the avatar use the provided image url.', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: [ + 'chat', + ], + operation: [ + 'postMessage', + ], + }, + }, + options: [ + { + displayName: 'Emoji', + name: 'emoji', + type: 'string', + default: '', + description: 'This will cause the message’s name to appear as the given alias, but your username will still display.', + } + ] + }, + { + displayName: 'Attachments', + name: 'attachments', + type: 'collection', + default: {}, + placeholder: 'Add Attachment Item', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Attachment', + + }, + displayOptions: { + show: { + resource: [ + 'chat', + ], + operation: [ + 'postMessage', + ], + }, + }, + options: [ + { + displayName: 'Color', + name: 'color', + type: 'string', + default: '', + description: 'The color you want the order on the left side to be, any value background-css supports.', + }, + { + displayName: 'Text', + name: 'text', + type: 'string', + default: '', + description: 'The text to display for this attachment, it is different than the message’s text.', + }, + { + displayName: 'Timestamp', + name: 'timestamp', + type: 'dateTime', + default: '', + description: 'Displays the time next to the text portion.', + }, + { + displayName: 'Thumb URL', + name: 'thumbUrl', + type: 'string', + default: '', + description: 'An image that displays to the left of the text, looks better when this is relatively small.', + }, + { + displayName: 'Message Link', + name: 'messageLink', + type: 'string', + default: '', + description: 'Only applicable if the timestamp is provided, as it makes the time clickable to this link.', + }, + { + displayName: 'Collapsed', + name: 'collapsed', + type: 'boolean', + default: false, + description: 'Causes the image, audio, and video sections to be hiding when collapsed is true.', + }, + { + displayName: 'Author Name', + name: 'authorName', + type: 'string', + default: '', + description: 'Name of the author.', + }, + { + displayName: 'Author Link', + name: 'authorLink', + type: 'string', + default: '', + description: 'Providing this makes the author name clickable and points to this link.', + }, + { + displayName: 'Author Icon', + name: 'authorIcon', + type: 'string', + default: '', + placeholder: 'https://site.com/img.png', + description: 'Displays a tiny icon to the left of the Author’s name.', + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + description: 'Title to display for this attachment, displays under the author.', + }, + { + displayName: 'Title Link', + name: 'titleLink', + type: 'string', + default: '', + description: 'Providing this makes the title clickable, pointing to this link.', + }, + { + displayName: 'Title Link Download', + name: 'titleLinkDownload', + type: 'boolean', + default: false, + description: 'When this is true, a download icon appears and clicking this saves the link to file.', + }, + { + displayName: 'Image URL', + name: 'imageUrl', + type: 'string', + default: '', + description: 'The image to display, will be “big” and easy to see.', + }, + { + displayName: 'Audio URL', + name: 'AudioUrl', + type: 'string', + default: '', + placeholder: 'https://site.com/aud.mp3', + description: 'Audio file to play, only supports what html audio does.', + }, + { + displayName: 'video URL', + name: 'videoUrl', + type: 'string', + default: '', + placeholder: 'https://site.com/vid.mp4', + description: 'Video file to play, only supports what html video does.', + }, + { + displayName: 'Fields', + name: 'fields', + type: 'fixedCollection', + placeholder: 'Add Field Item', + typeOptions: { + multipleValues: true, + }, + default: '', + options: [ + { + name: 'fieldsValues', + displayName: 'Fields', + values: [ + { + displayName: 'Short', + name: 'short', + type: 'boolean', + default: false, + description: 'Whether this field should be a short field.' + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + description: 'The title of this field.' + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + description: 'The value of this field, displayed underneath the title value.' + }, + ], + }, + ], + }, + ] + } ] }; diff --git a/packages/nodes-base/nodes/Rocketchat/rocketchat.png b/packages/nodes-base/nodes/Rocketchat/rocketchat.png index 93dfcacf17fb871a068195cc057ae93aa56fe6b3..7d298512958aa9fc0bf1351450e14b8ebe9bf910 100644 GIT binary patch delta 3885 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 delta 5418 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 U%-T*lJ^%m!07*qoM6N<$g0v8nw*UYD From e9613944db76e5de1b1fd2f8061104e5b1bada81 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Sat, 9 Nov 2019 20:29:05 -0500 Subject: [PATCH 3/5] :sparkles Done --- .../credentials/RocketchatApi.credentials.ts | 17 +- .../nodes/Rocketchat/GenericFunctions.ts | 28 ++- .../nodes/Rocketchat/Rocketchat.node.ts | 231 +++++++++++++++++- 3 files changed, 251 insertions(+), 25 deletions(-) diff --git a/packages/nodes-base/credentials/RocketchatApi.credentials.ts b/packages/nodes-base/credentials/RocketchatApi.credentials.ts index ab6d0019ed..0231d5a72b 100644 --- a/packages/nodes-base/credentials/RocketchatApi.credentials.ts +++ b/packages/nodes-base/credentials/RocketchatApi.credentials.ts @@ -9,10 +9,23 @@ export class RocketchatApi implements ICredentialType { displayName = 'Rocket API'; properties = [ { - displayName: 'API Key', - name: 'apiKey', + displayName: 'User Id', + name: 'userId', type: 'string' as NodePropertyTypes, default: '', }, + { + displayName: 'Auth Key', + name: 'authKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + { + displayName: 'Sub Domain', + name: 'subdomain', + type: 'string' as NodePropertyTypes, + default: '', + placeholder: 'n8n' + }, ]; } diff --git a/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts index 1e00514fc7..26688b6ff4 100644 --- a/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts @@ -5,34 +5,30 @@ import { IHookFunctions, ILoadOptionsFunctions, IExecuteSingleFunctions, - BINARY_ENCODING } from 'n8n-core'; -import * as _ from 'lodash'; - -export async function rocketchatApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, resource: string, method: string, body: any = {}, headers?: object): Promise { // tslint:disable-line:no-any +export async function rocketchatApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, resource: string, method: string, operation: string, body: any = {}, headers?: object): Promise { // tslint:disable-line:no-any const credentials = this.getCredentials('rocketchatApi'); if (credentials === undefined) { - throw new Error('No credentials got returned!'); + throw new Error('No credentials got returned!'); } - const apiKey = `${credentials.apiKey}:X`; + const headerWithAuthentication = Object.assign({}, headers, + { 'X-Auth-Token': credentials.authKey, 'X-User-Id': credentials.userId }); - const headerWithAuthentication = Object.assign({}, headers, { Authorization: `${Buffer.from(apiKey).toString(BINARY_ENCODING)}` }); - - const endpoint = ''; + const endpoint = 'rocket.chat/api/v1'; const options: OptionsWithUri = { headers: headerWithAuthentication, method, body, - uri: `https://${credentials.domain}.${endpoint}${resource}`, + uri: `https://${credentials.subdomain}.${endpoint}${resource}.${operation}`, json: true }; - if (_.isEmpty(options.body)) { + if (Object.keys(options.body).length === 0) { delete options.body; } @@ -49,3 +45,13 @@ export async function rocketchatApiRequest(this: IHookFunctions | IExecuteFuncti throw error.response.body; } } + +export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any + let result; + try { + result = JSON.parse(json!); + } catch (exception) { + result = []; + } + return result; +} diff --git a/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts index a0e5d2f4f4..d50e066a9d 100644 --- a/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts +++ b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts @@ -5,14 +5,46 @@ import { IDataObject, INodeTypeDescription, INodeExecutionData, - INodeType, - ILoadOptionsFunctions, - INodePropertyOptions, + INodeType } from 'n8n-workflow'; import { - rocketchatApiRequest + rocketchatApiRequest, + validateJSON } from './GenericFunctions'; +interface IField { + short?: boolean; + title?: string; + value?: string; +} + +interface IAttachment { + color?: string; + text?: string; + ts?: string; + title?: string; + thumb_url?: string; + message_link?: string; + collapsed?: boolean; + author_name?: string; + author_link?: string; + author_icon?: string; + title_link?: string; + title_link_download?: boolean; + image_url?: string; + audio_url?: string; + video_url?: string; + fields?: IField[]; +} + +interface IPostMessageBody { + channel: string; + text?: string; + alias?: string; + emoji?: string; + avatar?: string; + attachments?: IAttachment[]; +} export class Rocketchat implements INodeType { @@ -71,6 +103,24 @@ export class Rocketchat implements INodeType { default: '', description: 'The operation to perform.', }, + { + displayName: 'Channel', + name: 'channel', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'chat', + ], + operation: [ + 'postMessage' + ] + }, + }, + default: '', + description: 'TThe channel name with the prefix in front of it.', + }, { displayName: 'Alias', name: 'alias', @@ -105,6 +155,40 @@ export class Rocketchat implements INodeType { default: '', description: 'If provided, this will make the avatar use the provided image url.', }, + { + displayName: 'Text', + name: 'text', + type: 'string', + displayOptions: { + show: { + resource: [ + 'chat', + ], + operation: [ + 'postMessage' + ] + }, + }, + default: '', + description: 'The text of the message to send, is optional because of attachments.', + }, + { + displayName: 'JSON Parameters', + name: 'jsonParameters', + type: 'boolean', + default: false, + description: '', + displayOptions: { + show: { + resource: [ + 'chat' + ], + operation: [ + 'postMessage', + ] + }, + }, + }, { displayName: 'Options', name: 'options', @@ -149,6 +233,9 @@ export class Rocketchat implements INodeType { ], operation: [ 'postMessage', + ], + jsonParameters: [ + false ], }, }, @@ -169,7 +256,7 @@ export class Rocketchat implements INodeType { }, { displayName: 'Timestamp', - name: 'timestamp', + name: 'ts', type: 'dateTime', default: '', description: 'Displays the time next to the text portion.', @@ -247,7 +334,7 @@ export class Rocketchat implements INodeType { }, { displayName: 'Audio URL', - name: 'AudioUrl', + name: 'audioUrl', type: 'string', default: '', placeholder: 'https://site.com/aud.mp3', @@ -301,17 +388,137 @@ export class Rocketchat implements INodeType { ], }, ] + }, + { + displayName: 'Attachments', + name: 'attachmentsJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + displayOptions: { + show: { + resource: [ + 'chat' + ], + operation: [ + 'postMessage' + ], + jsonParameters: [ + true + ], + }, + }, + default: '', + required: false, + description: '', } ] }; - methods = { - - }; - async executeSingle(this: IExecuteSingleFunctions): Promise { + + const resource = this.getNodeParameter('resource') as string; + const opeation = this.getNodeParameter('operation') as string; + let response; + + if (resource === 'chat') { + //https://rocket.chat/docs/developer-guides/rest-api/chat/postmessage + if (opeation === 'postMessage') { + const channel = this.getNodeParameter('channel') as string; + const alias = this.getNodeParameter('alias') as string; + const avatar = this.getNodeParameter('avatar') as string; + const text = this.getNodeParameter('text') as string; + const options = this.getNodeParameter('options') as IDataObject; + const jsonActive = this.getNodeParameter('jsonParameters') as boolean; + + const body: IPostMessageBody = { + channel, + alias, + avatar, + text, + }; + + if (options.emoji) { + body.emoji = options.emoji as string; + } + + if (!jsonActive) { + const optionsAttachments = this.getNodeParameter('attachments') as IDataObject[]; + if (optionsAttachments.length > 0) { + const attachments: IAttachment[] = []; + for (let i = 0; i < optionsAttachments.length; i++) { + const attachment: IAttachment = {}; + for (const option of Object.keys(optionsAttachments[i])) { + if (option === 'color') { + attachment.color = optionsAttachments[i][option] as string; + } else if (option === 'text') { + attachment.text = optionsAttachments[i][option] as string; + } else if (option === 'ts') { + attachment.ts = optionsAttachments[i][option] as string; + } else if (option === 'messageLinks') { + attachment.message_link = optionsAttachments[i][option] as string; + } else if (option === 'thumbUrl') { + attachment.thumb_url = optionsAttachments[i][option] as string; + } else if (option === 'collapsed') { + attachment.collapsed = optionsAttachments[i][option] as boolean; + } else if (option === 'authorName') { + attachment.author_name = optionsAttachments[i][option] as string; + } else if (option === 'authorLink') { + attachment.author_link = optionsAttachments[i][option] as string; + } else if (option === 'authorIcon') { + attachment.author_icon = optionsAttachments[i][option] as string; + } else if (option === 'title') { + attachment.title = optionsAttachments[i][option] as string; + } else if (option === 'titleLink') { + attachment.title_link = optionsAttachments[i][option] as string; + } else if (option === 'titleLinkDownload') { + attachment.title_link_download = optionsAttachments[i][option] as boolean; + } else if (option === 'imageUrl') { + attachment.image_url = optionsAttachments[i][option] as string; + } else if (option === 'audioUrl') { + attachment.audio_url = optionsAttachments[i][option] as string; + } else if (option === 'videoUrl') { + attachment.video_url = optionsAttachments[i][option] as string; + } else if (option === 'fields') { + const fieldsValues = (optionsAttachments[i][option] as IDataObject).fieldsValues as IDataObject[]; + if (fieldsValues.length > 0) { + const fields: IField[] = []; + for (let i = 0; i < fieldsValues.length; i++) { + const field: IField = {}; + for (const key of Object.keys(fieldsValues[i])) { + if (key === 'short') { + field.short = fieldsValues[i][key] as boolean; + } else if (key === 'title') { + field.title = fieldsValues[i][key] as string; + } else if (key === 'value') { + field.value = fieldsValues[i][key] as string; + } + } + fields.push(field); + attachment.fields = fields; + } + } + } + } + attachments.push(attachment); + } + body.attachments = attachments; + } + } else { + body.attachments = validateJSON(this.getNodeParameter('attachmentsJson') as string); + } + + try { + response = await rocketchatApiRequest.call(this, '/chat', 'POST', 'postMessage', body); + } catch (err) { + throw new Error(`Rocketchat Error: ${err}`); + } + } + } + return { - json: {} - }; + json: response + }; } } From 11826d6a4e5e9bde52988d48f1feb25e1040223a Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Mon, 11 Nov 2019 00:00:24 -0500 Subject: [PATCH 4/5] fixed tabs issue --- .../nodes/Rocketchat/GenericFunctions.ts | 10 +- .../nodes/Rocketchat/Rocketchat.node.ts | 688 +++++++++--------- 2 files changed, 347 insertions(+), 351 deletions(-) diff --git a/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts index 26688b6ff4..b058e67e6c 100644 --- a/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts @@ -1,5 +1,4 @@ import { OptionsWithUri } from 'request'; - import { IExecuteFunctions, IHookFunctions, @@ -8,17 +7,16 @@ import { } from 'n8n-core'; export async function rocketchatApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, resource: string, method: string, operation: string, body: any = {}, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('rocketchatApi'); if (credentials === undefined) { - throw new Error('No credentials got returned!'); + throw new Error('No credentials got returned!'); } - const headerWithAuthentication = Object.assign({}, headers, - { 'X-Auth-Token': credentials.authKey, 'X-User-Id': credentials.userId }); + const headerWithAuthentication = Object.assign({}, headers, + { 'X-Auth-Token': credentials.authKey, 'X-User-Id': credentials.userId }); - const endpoint = 'rocket.chat/api/v1'; + const endpoint = 'rocket.chat/api/v1'; const options: OptionsWithUri = { headers: headerWithAuthentication, diff --git a/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts index d50e066a9d..feee34d68a 100644 --- a/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts +++ b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts @@ -7,47 +7,46 @@ import { INodeExecutionData, INodeType } from 'n8n-workflow'; -import { - rocketchatApiRequest, - validateJSON + import { + rocketchatApiRequest, + validateJSON } from './GenericFunctions'; interface IField { - short?: boolean; - title?: string; - value?: string; + short?: boolean; + title?: string; + value?: string; } interface IAttachment { - color?: string; + color?: string; text?: string; - ts?: string; - title?: string; - thumb_url?: string; - message_link?: string; - collapsed?: boolean; - author_name?: string; - author_link?: string; - author_icon?: string; - title_link?: string; - title_link_download?: boolean; - image_url?: string; - audio_url?: string; - video_url?: string; - fields?: IField[]; + ts?: string; + title?: string; + thumb_url?: string; + message_link?: string; + collapsed?: boolean; + author_name?: string; + author_link?: string; + author_icon?: string; + title_link?: string; + title_link_download?: boolean; + image_url?: string; + audio_url?: string; + video_url?: string; + fields?: IField[]; } interface IPostMessageBody { channel: string; text?: string; alias?: string; - emoji?: string; - avatar?: string; + emoji?: string; + avatar?: string; attachments?: IAttachment[]; } export class Rocketchat implements INodeType { - description: INodeTypeDescription = { displayName: 'Rocketchat', name: 'Rocketchat', @@ -67,9 +66,9 @@ export class Rocketchat implements INodeType { name: 'rocketchatApi', required: true, } - ], + ], properties: [ - { + { displayName: 'Resource', name: 'resource', type: 'options', @@ -102,26 +101,26 @@ export class Rocketchat implements INodeType { ], default: '', description: 'The operation to perform.', - }, - { + }, + { displayName: 'Channel', name: 'channel', - type: 'string', - required: true, + type: 'string', + required: true, displayOptions: { show: { resource: [ 'chat', - ], - operation: [ - 'postMessage' - ] + ], + operation: [ + 'postMessage' + ] }, }, default: '', description: 'TThe channel name with the prefix in front of it.', - }, - { + }, + { displayName: 'Alias', name: 'alias', type: 'string', @@ -129,16 +128,16 @@ export class Rocketchat implements INodeType { show: { resource: [ 'chat', - ], - operation: [ - 'postMessage' - ] + ], + operation: [ + 'postMessage' + ] }, }, default: '', description: 'This will cause the message’s name to appear as the given alias, but your username will still display.', - }, - { + }, + { displayName: 'Avatar', name: 'avatar', type: 'string', @@ -146,16 +145,16 @@ export class Rocketchat implements INodeType { show: { resource: [ 'chat', - ], - operation: [ - 'postMessage' - ] + ], + operation: [ + 'postMessage' + ] }, }, default: '', description: 'If provided, this will make the avatar use the provided image url.', - }, - { + }, + { displayName: 'Text', name: 'text', type: 'string', @@ -163,16 +162,16 @@ export class Rocketchat implements INodeType { show: { resource: [ 'chat', - ], - operation: [ - 'postMessage' - ] + ], + operation: [ + 'postMessage' + ] }, }, default: '', description: 'The text of the message to send, is optional because of attachments.', - }, - { + }, + { displayName: 'JSON Parameters', name: 'jsonParameters', type: 'boolean', @@ -189,7 +188,7 @@ export class Rocketchat implements INodeType { }, }, }, - { + { displayName: 'Options', name: 'options', type: 'collection', @@ -197,328 +196,327 @@ export class Rocketchat implements INodeType { default: {}, displayOptions: { show: { - resource: [ + resource: [ 'chat', - ], + ], operation: [ 'postMessage', - ], + ], }, }, options: [ - { - displayName: 'Emoji', - name: 'emoji', - type: 'string', - default: '', - description: 'This will cause the message’s name to appear as the given alias, but your username will still display.', - } - ] - }, - { + { + displayName: 'Emoji', + name: 'emoji', + type: 'string', + default: '', + description: 'This will cause the message’s name to appear as the given alias, but your username will still display.', + } + ] + }, + { displayName: 'Attachments', name: 'attachments', type: 'collection', - default: {}, - placeholder: 'Add Attachment Item', - typeOptions: { - multipleValues: true, - multipleValueButtonText: 'Add Attachment', + default: {}, + placeholder: 'Add Attachment Item', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Attachment', }, displayOptions: { show: { - resource: [ - 'chat', - ], + resource: [ + 'chat', + ], operation: [ 'postMessage', - ], - jsonParameters: [ - false - ], + ], + jsonParameters: [ + false + ], }, }, options: [ - { - displayName: 'Color', - name: 'color', - type: 'string', - default: '', - description: 'The color you want the order on the left side to be, any value background-css supports.', - }, - { - displayName: 'Text', - name: 'text', - type: 'string', - default: '', - description: 'The text to display for this attachment, it is different than the message’s text.', - }, - { - displayName: 'Timestamp', - name: 'ts', - type: 'dateTime', - default: '', - description: 'Displays the time next to the text portion.', - }, - { - displayName: 'Thumb URL', - name: 'thumbUrl', - type: 'string', - default: '', - description: 'An image that displays to the left of the text, looks better when this is relatively small.', - }, - { - displayName: 'Message Link', - name: 'messageLink', - type: 'string', - default: '', - description: 'Only applicable if the timestamp is provided, as it makes the time clickable to this link.', - }, - { - displayName: 'Collapsed', - name: 'collapsed', - type: 'boolean', - default: false, - description: 'Causes the image, audio, and video sections to be hiding when collapsed is true.', - }, - { - displayName: 'Author Name', - name: 'authorName', - type: 'string', - default: '', - description: 'Name of the author.', - }, - { - displayName: 'Author Link', - name: 'authorLink', - type: 'string', - default: '', - description: 'Providing this makes the author name clickable and points to this link.', - }, - { - displayName: 'Author Icon', - name: 'authorIcon', - type: 'string', - default: '', - placeholder: 'https://site.com/img.png', - description: 'Displays a tiny icon to the left of the Author’s name.', - }, - { - displayName: 'Title', - name: 'title', - type: 'string', - default: '', - description: 'Title to display for this attachment, displays under the author.', - }, - { - displayName: 'Title Link', - name: 'titleLink', - type: 'string', - default: '', - description: 'Providing this makes the title clickable, pointing to this link.', - }, - { - displayName: 'Title Link Download', - name: 'titleLinkDownload', - type: 'boolean', - default: false, - description: 'When this is true, a download icon appears and clicking this saves the link to file.', - }, - { - displayName: 'Image URL', - name: 'imageUrl', - type: 'string', - default: '', - description: 'The image to display, will be “big” and easy to see.', - }, - { - displayName: 'Audio URL', - name: 'audioUrl', - type: 'string', - default: '', - placeholder: 'https://site.com/aud.mp3', - description: 'Audio file to play, only supports what html audio does.', - }, - { - displayName: 'video URL', - name: 'videoUrl', - type: 'string', - default: '', - placeholder: 'https://site.com/vid.mp4', - description: 'Video file to play, only supports what html video does.', - }, - { - displayName: 'Fields', - name: 'fields', - type: 'fixedCollection', - placeholder: 'Add Field Item', - typeOptions: { - multipleValues: true, - }, - default: '', - options: [ - { - name: 'fieldsValues', - displayName: 'Fields', - values: [ - { - displayName: 'Short', - name: 'short', - type: 'boolean', - default: false, - description: 'Whether this field should be a short field.' - }, - { - displayName: 'Title', - name: 'title', - type: 'string', - default: '', - description: 'The title of this field.' - }, - { - displayName: 'Value', - name: 'value', - type: 'string', - default: '', - description: 'The value of this field, displayed underneath the title value.' - }, - ], - }, - ], - }, - ] - }, - { - displayName: 'Attachments', - name: 'attachmentsJson', - type: 'json', - typeOptions: { - alwaysOpenEditWindow: true, - }, - displayOptions: { - show: { - resource: [ - 'chat' - ], - operation: [ - 'postMessage' - ], - jsonParameters: [ - true - ], - }, - }, - default: '', - required: false, - description: '', - } - ] + { + displayName: 'Color', + name: 'color', + type: 'string', + default: '', + description: 'The color you want the order on the left side to be, any value background-css supports.', + }, + { + displayName: 'Text', + name: 'text', + type: 'string', + default: '', + description: 'The text to display for this attachment, it is different than the message’s text.', + }, + { + displayName: 'Timestamp', + name: 'ts', + type: 'dateTime', + default: '', + description: 'Displays the time next to the text portion.', + }, + { + displayName: 'Thumb URL', + name: 'thumbUrl', + type: 'string', + default: '', + description: 'An image that displays to the left of the text, looks better when this is relatively small.', + }, + { + displayName: 'Message Link', + name: 'messageLink', + type: 'string', + default: '', + description: 'Only applicable if the timestamp is provided, as it makes the time clickable to this link.', + }, + { + displayName: 'Collapsed', + name: 'collapsed', + type: 'boolean', + default: false, + description: 'Causes the image, audio, and video sections to be hiding when collapsed is true.', + }, + { + displayName: 'Author Name', + name: 'authorName', + type: 'string', + default: '', + description: 'Name of the author.', + }, + { + displayName: 'Author Link', + name: 'authorLink', + type: 'string', + default: '', + description: 'Providing this makes the author name clickable and points to this link.', + }, + { + displayName: 'Author Icon', + name: 'authorIcon', + type: 'string', + default: '', + placeholder: 'https://site.com/img.png', + description: 'Displays a tiny icon to the left of the Author’s name.', + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + description: 'Title to display for this attachment, displays under the author.', + }, + { + displayName: 'Title Link', + name: 'titleLink', + type: 'string', + default: '', + description: 'Providing this makes the title clickable, pointing to this link.', + }, + { + displayName: 'Title Link Download', + name: 'titleLinkDownload', + type: 'boolean', + default: false, + description: 'When this is true, a download icon appears and clicking this saves the link to file.', + }, + { + displayName: 'Image URL', + name: 'imageUrl', + type: 'string', + default: '', + description: 'The image to display, will be “big” and easy to see.', + }, + { + displayName: 'Audio URL', + name: 'audioUrl', + type: 'string', + default: '', + placeholder: 'https://site.com/aud.mp3', + description: 'Audio file to play, only supports what html audio does.', + }, + { + displayName: 'video URL', + name: 'videoUrl', + type: 'string', + default: '', + placeholder: 'https://site.com/vid.mp4', + description: 'Video file to play, only supports what html video does.', + }, + { + displayName: 'Fields', + name: 'fields', + type: 'fixedCollection', + placeholder: 'Add Field Item', + typeOptions: { + multipleValues: true, + }, + default: '', + options: [ + { + name: 'fieldsValues', + displayName: 'Fields', + values: [ + { + displayName: 'Short', + name: 'short', + type: 'boolean', + default: false, + description: 'Whether this field should be a short field.' + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + description: 'The title of this field.' + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + description: 'The value of this field, displayed underneath the title value.' + }, + ], + }, + ], + }, + ] + }, + { + displayName: 'Attachments', + name: 'attachmentsJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + displayOptions: { + show: { + resource: [ + 'chat' + ], + operation: [ + 'postMessage' + ], + jsonParameters: [ + true + ], + }, + }, + default: '', + required: false, + description: '', + } + ] }; async executeSingle(this: IExecuteSingleFunctions): Promise { - - const resource = this.getNodeParameter('resource') as string; + const resource = this.getNodeParameter('resource') as string; const opeation = this.getNodeParameter('operation') as string; let response; if (resource === 'chat') { - //https://rocket.chat/docs/developer-guides/rest-api/chat/postmessage - if (opeation === 'postMessage') { - const channel = this.getNodeParameter('channel') as string; - const alias = this.getNodeParameter('alias') as string; - const avatar = this.getNodeParameter('avatar') as string; - const text = this.getNodeParameter('text') as string; + //https://rocket.chat/docs/developer-guides/rest-api/chat/postmessage + if (opeation === 'postMessage') { + const channel = this.getNodeParameter('channel') as string; + const alias = this.getNodeParameter('alias') as string; + const avatar = this.getNodeParameter('avatar') as string; + const text = this.getNodeParameter('text') as string; const options = this.getNodeParameter('options') as IDataObject; const jsonActive = this.getNodeParameter('jsonParameters') as boolean; - const body: IPostMessageBody = { - channel, - alias, - avatar, - text, - }; + const body: IPostMessageBody = { + channel, + alias, + avatar, + text, + }; - if (options.emoji) { - body.emoji = options.emoji as string; - } + if (options.emoji) { + body.emoji = options.emoji as string; + } if (!jsonActive) { - const optionsAttachments = this.getNodeParameter('attachments') as IDataObject[]; - if (optionsAttachments.length > 0) { - const attachments: IAttachment[] = []; - for (let i = 0; i < optionsAttachments.length; i++) { - const attachment: IAttachment = {}; - for (const option of Object.keys(optionsAttachments[i])) { - if (option === 'color') { - attachment.color = optionsAttachments[i][option] as string; - } else if (option === 'text') { - attachment.text = optionsAttachments[i][option] as string; - } else if (option === 'ts') { - attachment.ts = optionsAttachments[i][option] as string; - } else if (option === 'messageLinks') { - attachment.message_link = optionsAttachments[i][option] as string; - } else if (option === 'thumbUrl') { - attachment.thumb_url = optionsAttachments[i][option] as string; - } else if (option === 'collapsed') { - attachment.collapsed = optionsAttachments[i][option] as boolean; - } else if (option === 'authorName') { - attachment.author_name = optionsAttachments[i][option] as string; - } else if (option === 'authorLink') { - attachment.author_link = optionsAttachments[i][option] as string; - } else if (option === 'authorIcon') { - attachment.author_icon = optionsAttachments[i][option] as string; - } else if (option === 'title') { - attachment.title = optionsAttachments[i][option] as string; - } else if (option === 'titleLink') { - attachment.title_link = optionsAttachments[i][option] as string; - } else if (option === 'titleLinkDownload') { - attachment.title_link_download = optionsAttachments[i][option] as boolean; - } else if (option === 'imageUrl') { - attachment.image_url = optionsAttachments[i][option] as string; - } else if (option === 'audioUrl') { - attachment.audio_url = optionsAttachments[i][option] as string; - } else if (option === 'videoUrl') { - attachment.video_url = optionsAttachments[i][option] as string; - } else if (option === 'fields') { - const fieldsValues = (optionsAttachments[i][option] as IDataObject).fieldsValues as IDataObject[]; - if (fieldsValues.length > 0) { - const fields: IField[] = []; - for (let i = 0; i < fieldsValues.length; i++) { - const field: IField = {}; - for (const key of Object.keys(fieldsValues[i])) { - if (key === 'short') { - field.short = fieldsValues[i][key] as boolean; - } else if (key === 'title') { - field.title = fieldsValues[i][key] as string; - } else if (key === 'value') { - field.value = fieldsValues[i][key] as string; - } - } - fields.push(field); - attachment.fields = fields; - } - } - } - } - attachments.push(attachment); - } - body.attachments = attachments; - } - } else { - body.attachments = validateJSON(this.getNodeParameter('attachmentsJson') as string); - } + const optionsAttachments = this.getNodeParameter('attachments') as IDataObject[]; + if (optionsAttachments.length > 0) { + const attachments: IAttachment[] = []; + for (let i = 0; i < optionsAttachments.length; i++) { + const attachment: IAttachment = {}; + for (const option of Object.keys(optionsAttachments[i])) { + if (option === 'color') { + attachment.color = optionsAttachments[i][option] as string; + } else if (option === 'text') { + attachment.text = optionsAttachments[i][option] as string; + } else if (option === 'ts') { + attachment.ts = optionsAttachments[i][option] as string; + } else if (option === 'messageLinks') { + attachment.message_link = optionsAttachments[i][option] as string; + } else if (option === 'thumbUrl') { + attachment.thumb_url = optionsAttachments[i][option] as string; + } else if (option === 'collapsed') { + attachment.collapsed = optionsAttachments[i][option] as boolean; + } else if (option === 'authorName') { + attachment.author_name = optionsAttachments[i][option] as string; + } else if (option === 'authorLink') { + attachment.author_link = optionsAttachments[i][option] as string; + } else if (option === 'authorIcon') { + attachment.author_icon = optionsAttachments[i][option] as string; + } else if (option === 'title') { + attachment.title = optionsAttachments[i][option] as string; + } else if (option === 'titleLink') { + attachment.title_link = optionsAttachments[i][option] as string; + } else if (option === 'titleLinkDownload') { + attachment.title_link_download = optionsAttachments[i][option] as boolean; + } else if (option === 'imageUrl') { + attachment.image_url = optionsAttachments[i][option] as string; + } else if (option === 'audioUrl') { + attachment.audio_url = optionsAttachments[i][option] as string; + } else if (option === 'videoUrl') { + attachment.video_url = optionsAttachments[i][option] as string; + } else if (option === 'fields') { + const fieldsValues = (optionsAttachments[i][option] as IDataObject).fieldsValues as IDataObject[]; + if (fieldsValues.length > 0) { + const fields: IField[] = []; + for (let i = 0; i < fieldsValues.length; i++) { + const field: IField = {}; + for (const key of Object.keys(fieldsValues[i])) { + if (key === 'short') { + field.short = fieldsValues[i][key] as boolean; + } else if (key === 'title') { + field.title = fieldsValues[i][key] as string; + } else if (key === 'value') { + field.value = fieldsValues[i][key] as string; + } + } + fields.push(field); + attachment.fields = fields; + } + } + } + } + attachments.push(attachment); + } + body.attachments = attachments; + } + } else { + body.attachments = validateJSON(this.getNodeParameter('attachmentsJson') as string); + } - try { - response = await rocketchatApiRequest.call(this, '/chat', 'POST', 'postMessage', body); - } catch (err) { - throw new Error(`Rocketchat Error: ${err}`); - } - } - } - - return { + try { + response = await rocketchatApiRequest.call(this, '/chat', 'POST', 'postMessage', body); + } catch (err) { + throw new Error(`Rocketchat Error: ${err}`); + } + } + } + + return { json: response }; - } + } } From d61fa934f8138a2ec0019f723afe82b422feca69 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 13 Nov 2019 22:29:52 +0100 Subject: [PATCH 5/5] :zap: Small changes like adding defaults and moving paramters --- .../nodes/Rocketchat/Rocketchat.node.ts | 70 +++++++------------ 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts index feee34d68a..5b05f8cb70 100644 --- a/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts +++ b/packages/nodes-base/nodes/Rocketchat/Rocketchat.node.ts @@ -78,7 +78,7 @@ export class Rocketchat implements INodeType { value: 'chat', }, ], - default: '', + default: 'chat', description: 'The resource to operate on.', }, { @@ -99,7 +99,7 @@ export class Rocketchat implements INodeType { description: 'Post a message to a channel or a direct message', }, ], - default: '', + default: 'postMessage', description: 'The operation to perform.', }, { @@ -118,41 +118,7 @@ export class Rocketchat implements INodeType { }, }, default: '', - description: 'TThe channel name with the prefix in front of it.', - }, - { - displayName: 'Alias', - name: 'alias', - type: 'string', - displayOptions: { - show: { - resource: [ - 'chat', - ], - operation: [ - 'postMessage' - ] - }, - }, - default: '', - description: 'This will cause the message’s name to appear as the given alias, but your username will still display.', - }, - { - displayName: 'Avatar', - name: 'avatar', - type: 'string', - displayOptions: { - show: { - resource: [ - 'chat', - ], - operation: [ - 'postMessage' - ] - }, - }, - default: '', - description: 'If provided, this will make the avatar use the provided image url.', + description: 'The channel name with the prefix in front of it.', }, { displayName: 'Text', @@ -205,6 +171,20 @@ export class Rocketchat implements INodeType { }, }, options: [ + { + displayName: 'Alias', + name: 'alias', + type: 'string', + default: '', + description: 'This will cause the message’s name to appear as the given alias, but your username will still display.', + }, + { + displayName: 'Avatar', + name: 'avatar', + type: 'string', + default: '', + description: 'If provided, this will make the avatar use the provided image url.', + }, { displayName: 'Emoji', name: 'emoji', @@ -242,8 +222,8 @@ export class Rocketchat implements INodeType { { displayName: 'Color', name: 'color', - type: 'string', - default: '', + type: 'color', + default: '#ff0000', description: 'The color you want the order on the left side to be, any value background-css supports.', }, { @@ -424,19 +404,21 @@ export class Rocketchat implements INodeType { //https://rocket.chat/docs/developer-guides/rest-api/chat/postmessage if (opeation === 'postMessage') { const channel = this.getNodeParameter('channel') as string; - const alias = this.getNodeParameter('alias') as string; - const avatar = this.getNodeParameter('avatar') as string; const text = this.getNodeParameter('text') as string; const options = this.getNodeParameter('options') as IDataObject; const jsonActive = this.getNodeParameter('jsonParameters') as boolean; const body: IPostMessageBody = { channel, - alias, - avatar, text, }; + if (options.alias) { + body.alias = options.alias as string; + } + if (options.avatar) { + body.avatar = options.avatar as string; + } if (options.emoji) { body.emoji = options.emoji as string; } @@ -514,7 +496,7 @@ export class Rocketchat implements INodeType { } } } - + return { json: response };