From b3dc6d9d9c640f1e0f04cb56d0fabe2aafb948b6 Mon Sep 17 00:00:00 2001 From: Albert Kiskorov Date: Sat, 7 May 2022 18:25:53 +0700 Subject: [PATCH] feat(Pushover Node): Add 'HTML Formatting' option and credential test (#3082) * Add html additional field https://pushover.net/api#html * :zap: replaced input type to boolean, added credential test * :zap: credentials and linter fixes * :zap: Improvements * :zap: Fix description Co-authored-by: Michael Kret Co-authored-by: ricardo --- .../credentials/PushoverApi.credentials.ts | 18 ++++++++++ .../nodes/Pushover/GenericFunctions.ts | 26 ++++++-------- .../nodes/Pushover/Pushover.node.ts | 32 ++++++++++++++---- .../nodes-base/nodes/Pushover/pushover.png | Bin 2753 -> 0 bytes .../nodes-base/nodes/Pushover/pushover.svg | 4 +++ 5 files changed, 59 insertions(+), 21 deletions(-) delete mode 100644 packages/nodes-base/nodes/Pushover/pushover.png create mode 100644 packages/nodes-base/nodes/Pushover/pushover.svg diff --git a/packages/nodes-base/credentials/PushoverApi.credentials.ts b/packages/nodes-base/credentials/PushoverApi.credentials.ts index 9cd9ba589d030..53a0c1e1e6a8d 100644 --- a/packages/nodes-base/credentials/PushoverApi.credentials.ts +++ b/packages/nodes-base/credentials/PushoverApi.credentials.ts @@ -1,5 +1,8 @@ import { + ICredentialDataDecryptedObject, + ICredentialTestRequest, ICredentialType, + IHttpRequestOptions, INodeProperties, } from 'n8n-workflow'; @@ -15,4 +18,19 @@ export class PushoverApi implements ICredentialType { default: '', }, ]; + async authenticate(credentials: ICredentialDataDecryptedObject, requestOptions: IHttpRequestOptions): Promise { + if (requestOptions.method === 'GET') { + Object.assign(requestOptions.qs, { token: credentials.apiKey }); + } else { + Object.assign(requestOptions.body, { token: credentials.apiKey }); + } + return requestOptions; + } + test: ICredentialTestRequest = { + request: { + baseURL: 'https://api.pushover.net/1', + url: '=/licenses.json?token={{$credentials?.apiKey}}', + method: 'GET', + }, + }; } diff --git a/packages/nodes-base/nodes/Pushover/GenericFunctions.ts b/packages/nodes-base/nodes/Pushover/GenericFunctions.ts index 5b08c58397233..421a7bd9ed657 100644 --- a/packages/nodes-base/nodes/Pushover/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Pushover/GenericFunctions.ts @@ -9,32 +9,28 @@ import { } from 'n8n-core'; import { - IDataObject, NodeApiError, + IDataObject, IHttpRequestMethods, IHttpRequestOptions, NodeApiError, } from 'n8n-workflow'; -export async function pushoverApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any +export async function pushoverApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: IHttpRequestMethods, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = await this.getCredentials('pushoverApi'); - - if (method === 'GET') { - qs.token = credentials.apiKey; - } else { - body.token = credentials.apiKey as string; - } - - const options: OptionsWithUri = { + const options: IHttpRequestOptions = { + headers: { + 'Content-Type': 'multipart/form-data', + }, method, - formData: body, + body, qs, - uri: `https://api.pushover.net/1${path}`, + url: `https://api.pushover.net/1${path}`, json: true, }; + try { if (Object.keys(body).length === 0) { delete options.body; } - //@ts-ignore - return await this.helpers.request.call(this, options); + + return await this.helpers.requestWithAuthentication.call(this, 'pushoverApi', options); } catch (error) { throw new NodeApiError(this.getNode(), error); } diff --git a/packages/nodes-base/nodes/Pushover/Pushover.node.ts b/packages/nodes-base/nodes/Pushover/Pushover.node.ts index 8853d31ac6458..0168288d39a32 100644 --- a/packages/nodes-base/nodes/Pushover/Pushover.node.ts +++ b/packages/nodes-base/nodes/Pushover/Pushover.node.ts @@ -22,7 +22,7 @@ export class Pushover implements INodeType { description: INodeTypeDescription = { displayName: 'Pushover', name: 'pushover', - icon: 'file:pushover.png', + icon: 'file:pushover.svg', group: ['input'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', @@ -43,6 +43,7 @@ export class Pushover implements INodeType { displayName: 'Resource', name: 'resource', type: 'options', + noDataExpression: true, options: [ { name: 'Message', @@ -50,12 +51,13 @@ export class Pushover implements INodeType { }, ], default: 'message', - description: 'The resource to operate on.', + description: 'The resource to operate on', }, { displayName: 'Operation', name: 'operation', type: 'options', + noDataExpression: true, displayOptions: { show: { resource: [ @@ -70,7 +72,7 @@ export class Pushover implements INodeType { }, ], default: 'push', - description: 'The resource to operate on.', + description: 'The resource to operate on', }, { displayName: 'User Key', @@ -149,7 +151,7 @@ export class Pushover implements INodeType { description: 'Send as -2 to generate no notification/alert, -1 to always send as a quiet notification, 1 to display as high-priority and bypass the user\'s quiet hours, or 2 to also require confirmation from the user', }, { - displayName: 'Retry (seconds)', + displayName: 'Retry (Seconds)', name: 'retry', type: 'number', typeOptions: { @@ -173,7 +175,7 @@ export class Pushover implements INodeType { description: 'Specifies how often (in seconds) the Pushover servers will send the same notification to the user. This parameter must have a value of at least 30 seconds between retries.', }, { - displayName: 'Expire (seconds)', + displayName: 'Expire (Seconds)', name: 'expire', type: 'number', typeOptions: { @@ -247,6 +249,13 @@ export class Pushover implements INodeType { default: '', description: 'Your user\'s device name to send the message directly to that device, rather than all of the user\'s devices (multiple devices may be separated by a comma)', }, + { + displayName: 'HTML Formatting', + name: 'html', + type: 'boolean', + default: false, + description: 'Whether to enable messages formatting with HTML tags', + }, { displayName: 'Sound', name: 'sound', @@ -257,6 +266,13 @@ export class Pushover implements INodeType { default: '', description: 'The name of one of the sounds supported by device clients to override the user\'s default sound choice', }, + { + displayName: 'Timestamp', + name: 'timestamp', + type: 'dateTime', + default: '', + description: 'A Unix timestamp of your message\'s date and time to display to the user, rather than the time your message is received by our API', + }, { displayName: 'Title', name: 'title', @@ -276,7 +292,7 @@ export class Pushover implements INodeType { name: 'url', type: 'string', default: '', - description: 'a supplementary URL to show with your message', + description: 'A supplementary URL to show with your message', }, { displayName: 'URL Title', @@ -326,6 +342,10 @@ export class Pushover implements INodeType { const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + if (additionalFields.html !== undefined) { + additionalFields.html = additionalFields.html ? '1' : ''; + } + const body: IDataObject = { user: userKey, message, diff --git a/packages/nodes-base/nodes/Pushover/pushover.png b/packages/nodes-base/nodes/Pushover/pushover.png deleted file mode 100644 index 6eb277a25f3b93658650094154d73abcc364675b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2753 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 diff --git a/packages/nodes-base/nodes/Pushover/pushover.svg b/packages/nodes-base/nodes/Pushover/pushover.svg new file mode 100644 index 0000000000000..4d262ce497f02 --- /dev/null +++ b/packages/nodes-base/nodes/Pushover/pushover.svg @@ -0,0 +1,4 @@ + + + +