From 14ab90791e682ba4bb56ff14df593cc71009ba70 Mon Sep 17 00:00:00 2001 From: trojanh Date: Tue, 21 Jan 2020 19:23:54 +0530 Subject: [PATCH 1/5] Add Disqus Forums GET apis --- .../credentials/DisqusApi.credentials.ts | 18 + .../nodes-base/nodes/Disqus/Disqus.node.ts | 626 ++++++++++++++++++ packages/nodes-base/nodes/Disqus/disqus.png | Bin 0 -> 1142 bytes packages/nodes-base/package.json | 2 + 4 files changed, 646 insertions(+) create mode 100644 packages/nodes-base/credentials/DisqusApi.credentials.ts create mode 100644 packages/nodes-base/nodes/Disqus/Disqus.node.ts create mode 100644 packages/nodes-base/nodes/Disqus/disqus.png diff --git a/packages/nodes-base/credentials/DisqusApi.credentials.ts b/packages/nodes-base/credentials/DisqusApi.credentials.ts new file mode 100644 index 0000000000..fbf98c92a2 --- /dev/null +++ b/packages/nodes-base/credentials/DisqusApi.credentials.ts @@ -0,0 +1,18 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class DisqusApi implements ICredentialType { + name = 'disqusApi'; + displayName = 'Disqus API'; + properties = [ + { + displayName: 'Access Token', + name: 'accessToken', + type: 'string' as NodePropertyTypes, + default: '', + description: 'Visit your account details page, and grab the Access Token. See Disqus auth.' + }, + ]; +} diff --git a/packages/nodes-base/nodes/Disqus/Disqus.node.ts b/packages/nodes-base/nodes/Disqus/Disqus.node.ts new file mode 100644 index 0000000000..401aabb169 --- /dev/null +++ b/packages/nodes-base/nodes/Disqus/Disqus.node.ts @@ -0,0 +1,626 @@ +import { + BINARY_ENCODING, + IExecuteFunctions, +} from 'n8n-core'; +import { + IDataObject, + INodeTypeDescription, + INodeExecutionData, + INodeType, +} from 'n8n-workflow'; + +import { OptionsWithUri } from 'request'; + + +export class Disqus implements INodeType { + description: INodeTypeDescription = { + displayName: 'Disqus', + name: 'disqus', + icon: 'file:disqus.png', + group: ['input'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Access data on Disqus', + defaults: { + name: 'Disqus', + color: '#22BB44', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'disqusApi', + required: true, + } + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Forum', + value: 'forum', + }, + { + name: 'User', + value: 'user', + }, + ], + default: 'forum', + description: 'The resource to operate on.', + }, + + // ---------------------------------- + // forum + // ---------------------------------- + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'forum', + ], + }, + }, + options: [ + { + name: 'Get', + value: 'get', + description: 'Returns forum details.', + }, + { + name: 'Get All Categories', + value: 'getCategories', + description: 'Returns a list of categories within a forum.', + }, + { + name: 'Get All Threads', + value: 'getThreads', + description: 'Returns a list of threads within a forum.', + }, + { + name: 'Get All Posts', + value: 'getPosts', + description: 'Returns a list of posts within a forum.', + } + ], + default: 'get', + description: 'The operation to perform.', + }, + + // ---------------------------------- + // forum:get + // ---------------------------------- + { + displayName: 'Forum name', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'forum', + ], + }, + }, + description: 'The short name(aka ID) of the forum to get.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'forum', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'attach', + name: 'attach', + type: 'string', + default: '[]', + description: 'Choices: followsForum, forumCanDisableAds, forumForumCategory, counters, forumDaysAlive, forumFeatures, forumIntegration, forumNewPolicy, forumPermissions', + }, + { + displayName: 'related', + name: 'related', + type: 'string', + default: false, + description: 'You may specify relations to include with your response. Choices `author`', + }, + ], + }, + + // ---------------------------------- + // forum:getPosts + // ---------------------------------- + { + displayName: 'Forum name', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getPosts', + ], + resource: [ + 'forum', + ], + }, + }, + description: 'The short name(aka ID) of the forum to get.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'getPosts', + ], + resource: [ + 'forum', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Since', + name: 'since', + type: 'string', + default: `[]`, + description: 'Unix timestamp (or ISO datetime standard)', + }, + { + displayName: 'Related', + name: 'related', + type: 'string', + default: '[]', + description: 'You may specify relations to include with your response. Choices `author`', + }, + { + displayName: 'Cursor', + name: 'cursor', + type: 'string', + default: '', + description: 'You may specify cursor for your response.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'string', + default: 25, + description: 'You may specify relations maximum number of posts to return. Maximum value is 100', + }, + { + displayName: 'Filters', + name: 'filters', + type: 'string', + default: '[]', + description: 'You may specify filters for your response. Choices: `Is_Anonymous`, `Has_Link`, `Has_Low_Rep_Author`, `Has_Bad_Word`, `Is_Flagged`, `No_Issue`, `Is_Toxic`, `Modified_By_Rule`, `Shadow_Banned`, `Has_Media`, `Is_At_Flag_Limit`', + }, + { + displayName: 'Query', + name: 'query', + type: 'string', + default: '', + description: 'You may specify query for your response.', + }, + { + displayName: 'Include', + name: 'include', + type: 'string', + default: false, + description: 'You may specify relations to include with your response. Choices `author`', + }, + { + displayName: 'Order', + name: 'order', + type: 'string', + default: 'asc', + description: 'You may specify order to sort your response.Choices: asc, desc', + }, + ], + }, + + // ---------------------------------- + // forum:getCategories + // ---------------------------------- + { + displayName: 'Forum name', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getCategories', + ], + resource: [ + 'forum', + ], + }, + }, + description: 'The short name(aka ID) of the forum to get Categories.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'getCategories', + ], + resource: [ + 'forum', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Since ID', + name: 'sinceId', + type: 'string', + default: `[]`, + description: 'You may specify cursor since_id for your response.', + }, + { + displayName: 'Cursor', + name: 'cursor', + type: 'string', + default: '', + description: 'You may specify cursor for your response.', + }, + { + displayName: 'Order', + name: 'order', + type: 'string', + default: 'asc', + description: 'You may specify order to sort your response.Choices: asc, desc', + }, + ], + }, + + // ---------------------------------- + // forum:getThreads + // ---------------------------------- + { + displayName: 'Forum name', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getThreads', + ], + resource: [ + 'forum', + ], + }, + }, + description: 'The short name(aka ID) of the forum to get Threads.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'getThreads', + ], + resource: [ + 'forum', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Thread', + name: 'threadId', + type: 'string', + default: '', + description: 'Looks up a thread by ID. You may pass us the "ident" query type instead of an ID by including "forum". You may pass us the "link" query type to filter by URL. You must pass the "forum" if you do not have the Pro API Access addon.', + }, + { + displayName: 'Since', + name: 'since', + type: 'string', + default: '', + description: 'Unix timestamp (or ISO datetime standard)', + }, + { + displayName: 'Related', + name: 'related', + type: 'string', + default: '[]', + description: 'You may specify relations to include with your response. Choices `author`', + }, + { + displayName: 'Cursor', + name: 'cursor', + type: 'string', + default: '', + description: 'You may specify cursor for your response.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'string', + default: 25, + description: 'You may specify relations maximum number of posts to return. Maximum value is 100', + }, + { + displayName: 'Include', + name: 'include', + type: 'string', + default: '', + description: 'You may specify relations to include with your response. Choices: open, closed, killed', + }, + { + displayName: 'Order', + name: 'order', + type: 'string', + default: 'desc', + description: 'You may specify order to sort your response.Choices: asc, desc', + }, + ], + }, + + // // ---------------------------------- + // // forum:getThreads + // // ---------------------------------- + // { + // displayName: 'Forum name', + // name: 'id', + // type: 'string', + // default: '', + // required: true, + // displayOptions: { + // show: { + // operation: [ + // 'getThreads', + // ], + // resource: [ + // 'forum', + // ], + // }, + // }, + // description: 'The short name(aka ID) of the forum to get Threads.', + // }, + // { + // displayName: 'Additional Fields', + // name: 'additionalFields', + // type: 'collection', + // placeholder: 'Add Field', + // displayOptions: { + // show: { + // operation: [ + // 'getCategories', + // ], + // resource: [ + // 'forum', + // ], + // }, + // }, + // default: {}, + // options: [ + // { + // displayName: 'Thread', + // name: 'threadId', + // type: 'string', + // default: '', + // description: 'Looks up a thread by ID. You may pass us the "ident" query type instead of an ID by including "forum". You may pass us the "link" query type to filter by URL. You must pass the "forum" if you do not have the Pro API Access addon.', + // }, + // { + // displayName: 'Since', + // name: 'since', + // type: 'string', + // default: '', + // description: 'Unix timestamp (or ISO datetime standard)', + // }, + // { + // displayName: 'Related', + // name: 'related', + // type: 'string', + // default: '[]', + // description: 'You may specify relations to include with your response. Choices `author`', + // }, + // { + // displayName: 'Cursor', + // name: 'cursor', + // type: 'string', + // default: '', + // description: 'You may specify cursor for your response.', + // }, + // { + // displayName: 'Limit', + // name: 'limit', + // type: 'string', + // default: 25, + // description: 'You may specify relations maximum number of posts to return. Maximum value is 100', + // }, + // { + // displayName: 'Include', + // name: 'include', + // type: 'string', + // default: '', + // description: 'You may specify relations to include with your response. Choices: open, closed, killed', + // }, + // { + // displayName: 'Order', + // name: 'order', + // type: 'string', + // default: 'desc', + // description: 'You may specify order to sort your response.Choices: asc, desc', + // }, + // ], + // }, + ], + }; + + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + + const credentials = this.getCredentials('disqusApi'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + + let endpoint = ''; + let requestMethod = ''; + let body: IDataObject | Buffer; + let qs: IDataObject; + + + for (let i = 0; i < items.length; i++) { + body = {}; + qs = {}; + + if (resource === 'forum') { + if (operation === 'get') { + // ---------------------------------- + // get + // ---------------------------------- + + requestMethod = 'GET'; + + endpoint = 'forums/details.json'; + + const id = this.getNodeParameter('id', i) as string; + qs.forum = id; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + Object.assign(qs, additionalFields); + + } else if (operation === 'getPosts') { + // ---------------------------------- + // getPosts + // ---------------------------------- + + requestMethod = 'GET'; + + endpoint = 'forums/listPosts.json'; + + const id = this.getNodeParameter('id', i) as string; + qs.forum = id; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + Object.assign(qs, additionalFields); + + } else if (operation === 'getCategories') { + // ---------------------------------- + // getCategories + // ---------------------------------- + + requestMethod = 'GET'; + + endpoint = 'forums/listCategories.json'; + + const id = this.getNodeParameter('id', i) as string; + qs.forum = id; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + Object.assign(qs, additionalFields); + + } else if (operation === 'getThreads') { + // ---------------------------------- + // getThreads + // ---------------------------------- + + requestMethod = 'GET'; + + endpoint = 'forums/listThreads.json'; + + const id = this.getNodeParameter('id', i) as string; + qs.forum = id; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + Object.assign(qs, additionalFields); + + } else { + throw new Error(`The operation "${operation}" is not known!`); + } + + } else { + throw new Error(`The resource "${resource}" is not known!`); + } + + qs.api_key = credentials.accessToken; + endpoint = `https://disqus.com/api/3.0/${endpoint}`; + + const options: OptionsWithUri = { + method: requestMethod, + qs, + uri: endpoint, + json: true, + }; + + + let responseData; + try { + responseData = await this.helpers.request(options); + } catch (error) { + if (error.statusCode === 401) { + // Return a clear error + throw new Error('The Dropbox credentials are not valid!'); + } + + if (error.error && error.error.error_summary) { + // Try to return the error prettier + throw new Error(`Dropbox error response [${error.statusCode}]: ${error.error.error_summary}`); + } + + // If that data does not exist for some reason return the actual error + throw error; + } + + if (responseData && Array.isArray(responseData)) { + returnData.push.apply(returnData, responseData as IDataObject[]); + } else { + returnData.push(responseData as IDataObject); + } + } + + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Disqus/disqus.png b/packages/nodes-base/nodes/Disqus/disqus.png new file mode 100644 index 0000000000000000000000000000000000000000..2b3b5cf3a898d43abfde7409f90d6e2c844a03ea GIT binary patch literal 1142 zcmV-+1d02JP)Px#8&FJCMJk~G|NsB;`TvN?|Fqu!XS)AHtpCmF|J(2X zSe;t>000B|NklP{?ZmIfroehFtOB^7qpA;Guo#Q?>QrmIX^mv^|Xn z_T!W>8sD<;jSSXgxd(TcY-=_Ws)CvV`h2dDf?Dojok621BaaM3EBa$ic|A4Ug!@;k z;beUu>*QXx59l>y3zloc_met@x|6lfu@#sFhO!XuE>!iJQ% z>D1f+VM9$<;b#KzU!{-~>LQfCmo;4_p9wq|UMSS3R6;c3YT0y`FA^vgMhM*rFa)-$ zg7}7l#m0wQ2)sJsE7=KBfDzbdP>#~;Py}`vl->Ba7e^$4U3rx2#R4U;XVb#H8MkFb zn+fc!Xi>+<2`HApPFyT|*>D7QGUu5}UiKDv zg_~AkC$=idQ9yPVmRij6Mv#zE2)s=0Dm}T&O|MrJfJm=XA2@3N9P(Jtd}0!VCnn}2 zUknS~1(?sQRqF&j)w3SDQ}rK%iX~X324YoeKq~eSvtkcQxlK#S6Rc{EQ1H|uKd|Nu zUUJsdiV3Xx0~h_ZHBuvs{-6X}rwAa+E`cW0Jc0sQ_=7JHwbZ*_Qma=HxwsG>oJ+r+D^Jh4T-K zyi7l?^D_Uy)XVfEYY%8)l%c_0IrAUJGuY(msRw6waTs%S`ThN3=Hc<*&lnSr?|)!% z`vHaZ`Zv`NDE#0t?N3-Z91e%W;cz${4u`|xa5x+ehr{t2ANt8T>t{X?82|tP07*qo IM6N<$f~#U7mH+?% literal 0 HcmV?d00001 diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index df87d196ce..c985f4bf97 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -37,6 +37,7 @@ "dist/credentials/ClickUpApi.credentials.js", "dist/credentials/CodaApi.credentials.js", "dist/credentials/CopperApi.credentials.js", + "dist/credentials/DisqusApi.credentials.js", "dist/credentials/DropboxApi.credentials.js", "dist/credentials/EventbriteApi.credentials.js", "dist/credentials/FreshdeskApi.credentials.js", @@ -104,6 +105,7 @@ "dist/nodes/Copper/CopperTrigger.node.js", "dist/nodes/Cron.node.js", "dist/nodes/Discord/Discord.node.js", + "dist/nodes/Disqus/Disqus.node.js", "dist/nodes/Dropbox/Dropbox.node.js", "dist/nodes/EditImage.node.js", "dist/nodes/EmailReadImap.node.js", From 4977c0b1630dc4f1dbc9c06e724903267cc42fa3 Mon Sep 17 00:00:00 2001 From: trojanh Date: Tue, 21 Jan 2020 19:33:57 +0530 Subject: [PATCH 2/5] Remove Users API from UI --- .../nodes-base/nodes/Disqus/Disqus.node.ts | 98 +------------------ 1 file changed, 2 insertions(+), 96 deletions(-) diff --git a/packages/nodes-base/nodes/Disqus/Disqus.node.ts b/packages/nodes-base/nodes/Disqus/Disqus.node.ts index 401aabb169..5e6561a6f0 100644 --- a/packages/nodes-base/nodes/Disqus/Disqus.node.ts +++ b/packages/nodes-base/nodes/Disqus/Disqus.node.ts @@ -42,11 +42,7 @@ export class Disqus implements INodeType { { name: 'Forum', value: 'forum', - }, - { - name: 'User', - value: 'user', - }, + } ], default: 'forum', description: 'The resource to operate on.', @@ -394,97 +390,7 @@ export class Disqus implements INodeType { description: 'You may specify order to sort your response.Choices: asc, desc', }, ], - }, - - // // ---------------------------------- - // // forum:getThreads - // // ---------------------------------- - // { - // displayName: 'Forum name', - // name: 'id', - // type: 'string', - // default: '', - // required: true, - // displayOptions: { - // show: { - // operation: [ - // 'getThreads', - // ], - // resource: [ - // 'forum', - // ], - // }, - // }, - // description: 'The short name(aka ID) of the forum to get Threads.', - // }, - // { - // displayName: 'Additional Fields', - // name: 'additionalFields', - // type: 'collection', - // placeholder: 'Add Field', - // displayOptions: { - // show: { - // operation: [ - // 'getCategories', - // ], - // resource: [ - // 'forum', - // ], - // }, - // }, - // default: {}, - // options: [ - // { - // displayName: 'Thread', - // name: 'threadId', - // type: 'string', - // default: '', - // description: 'Looks up a thread by ID. You may pass us the "ident" query type instead of an ID by including "forum". You may pass us the "link" query type to filter by URL. You must pass the "forum" if you do not have the Pro API Access addon.', - // }, - // { - // displayName: 'Since', - // name: 'since', - // type: 'string', - // default: '', - // description: 'Unix timestamp (or ISO datetime standard)', - // }, - // { - // displayName: 'Related', - // name: 'related', - // type: 'string', - // default: '[]', - // description: 'You may specify relations to include with your response. Choices `author`', - // }, - // { - // displayName: 'Cursor', - // name: 'cursor', - // type: 'string', - // default: '', - // description: 'You may specify cursor for your response.', - // }, - // { - // displayName: 'Limit', - // name: 'limit', - // type: 'string', - // default: 25, - // description: 'You may specify relations maximum number of posts to return. Maximum value is 100', - // }, - // { - // displayName: 'Include', - // name: 'include', - // type: 'string', - // default: '', - // description: 'You may specify relations to include with your response. Choices: open, closed, killed', - // }, - // { - // displayName: 'Order', - // name: 'order', - // type: 'string', - // default: 'desc', - // description: 'You may specify order to sort your response.Choices: asc, desc', - // }, - // ], - // }, + } ], }; From 0c1428471dd7faa2769115255cb5bce5d42db41c Mon Sep 17 00:00:00 2001 From: trojanh Date: Tue, 21 Jan 2020 19:40:20 +0530 Subject: [PATCH 3/5] Fix error messages --- packages/nodes-base/nodes/Disqus/Disqus.node.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodes-base/nodes/Disqus/Disqus.node.ts b/packages/nodes-base/nodes/Disqus/Disqus.node.ts index 5e6561a6f0..dde4b33965 100644 --- a/packages/nodes-base/nodes/Disqus/Disqus.node.ts +++ b/packages/nodes-base/nodes/Disqus/Disqus.node.ts @@ -508,12 +508,12 @@ export class Disqus implements INodeType { } catch (error) { if (error.statusCode === 401) { // Return a clear error - throw new Error('The Dropbox credentials are not valid!'); + throw new Error('The Disqus credentials are not valid!'); } if (error.error && error.error.error_summary) { // Try to return the error prettier - throw new Error(`Dropbox error response [${error.statusCode}]: ${error.error.error_summary}`); + throw new Error(`Disqus error response [${error.statusCode}]: ${error.error.error_summary}`); } // If that data does not exist for some reason return the actual error From c0aacbed746e8630ec065fd0ebd5a869245e59b3 Mon Sep 17 00:00:00 2001 From: trojanh Date: Tue, 21 Jan 2020 19:42:28 +0530 Subject: [PATCH 4/5] Update space indentation to tab --- .../credentials/DisqusApi.credentials.ts | 2 +- .../nodes-base/nodes/Disqus/Disqus.node.ts | 110 +++++++++--------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/packages/nodes-base/credentials/DisqusApi.credentials.ts b/packages/nodes-base/credentials/DisqusApi.credentials.ts index fbf98c92a2..c4b2f33aed 100644 --- a/packages/nodes-base/credentials/DisqusApi.credentials.ts +++ b/packages/nodes-base/credentials/DisqusApi.credentials.ts @@ -11,7 +11,7 @@ export class DisqusApi implements ICredentialType { displayName: 'Access Token', name: 'accessToken', type: 'string' as NodePropertyTypes, - default: '', + default: '', description: 'Visit your account details page, and grab the Access Token. See Disqus auth.' }, ]; diff --git a/packages/nodes-base/nodes/Disqus/Disqus.node.ts b/packages/nodes-base/nodes/Disqus/Disqus.node.ts index dde4b33965..85eb133def 100644 --- a/packages/nodes-base/nodes/Disqus/Disqus.node.ts +++ b/packages/nodes-base/nodes/Disqus/Disqus.node.ts @@ -63,16 +63,16 @@ export class Disqus implements INodeType { }, }, options: [ - { + { name: 'Get', value: 'get', description: 'Returns forum details.', - }, - { + }, + { name: 'Get All Categories', value: 'getCategories', description: 'Returns a list of categories within a forum.', - }, + }, { name: 'Get All Threads', value: 'getThreads', @@ -194,43 +194,43 @@ export class Disqus implements INodeType { type: 'string', default: '[]', description: 'You may specify relations to include with your response. Choices `author`', - }, - { + }, + { displayName: 'Cursor', name: 'cursor', - type: 'string', + type: 'string', default: '', description: 'You may specify cursor for your response.', - }, - { + }, + { displayName: 'Limit', name: 'limit', type: 'string', default: 25, description: 'You may specify relations maximum number of posts to return. Maximum value is 100', - }, - { + }, + { displayName: 'Filters', name: 'filters', type: 'string', default: '[]', - description: 'You may specify filters for your response. Choices: `Is_Anonymous`, `Has_Link`, `Has_Low_Rep_Author`, `Has_Bad_Word`, `Is_Flagged`, `No_Issue`, `Is_Toxic`, `Modified_By_Rule`, `Shadow_Banned`, `Has_Media`, `Is_At_Flag_Limit`', - }, - { + description: 'You may specify filters for your response. Choices: `Is_Anonymous`, `Has_Link`, `Has_Low_Rep_Author`, `Has_Bad_Word`, `Is_Flagged`, `No_Issue`, `Is_Toxic`, `Modified_By_Rule`, `Shadow_Banned`, `Has_Media`, `Is_At_Flag_Limit`', + }, + { displayName: 'Query', name: 'query', type: 'string', default: '', description: 'You may specify query for your response.', - }, - { + }, + { displayName: 'Include', name: 'include', type: 'string', default: false, description: 'You may specify relations to include with your response. Choices `author`', - }, - { + }, + { displayName: 'Order', name: 'order', type: 'string', @@ -238,9 +238,9 @@ export class Disqus implements INodeType { description: 'You may specify order to sort your response.Choices: asc, desc', }, ], - }, + }, - // ---------------------------------- + // ---------------------------------- // forum:getCategories // ---------------------------------- { @@ -285,14 +285,14 @@ export class Disqus implements INodeType { default: `[]`, description: 'You may specify cursor since_id for your response.', }, - { + { displayName: 'Cursor', name: 'cursor', - type: 'string', + type: 'string', default: '', description: 'You may specify cursor for your response.', - }, - { + }, + { displayName: 'Order', name: 'order', type: 'string', @@ -300,9 +300,9 @@ export class Disqus implements INodeType { description: 'You may specify order to sort your response.Choices: asc, desc', }, ], - }, + }, - // ---------------------------------- + // ---------------------------------- // forum:getThreads // ---------------------------------- { @@ -339,8 +339,8 @@ export class Disqus implements INodeType { }, }, default: {}, - options: [ - { + options: [ + { displayName: 'Thread', name: 'threadId', type: 'string', @@ -360,29 +360,29 @@ export class Disqus implements INodeType { type: 'string', default: '[]', description: 'You may specify relations to include with your response. Choices `author`', - }, - { + }, + { displayName: 'Cursor', name: 'cursor', - type: 'string', + type: 'string', default: '', description: 'You may specify cursor for your response.', - }, - { + }, + { displayName: 'Limit', name: 'limit', type: 'string', default: 25, description: 'You may specify relations maximum number of posts to return. Maximum value is 100', - }, - { + }, + { displayName: 'Include', name: 'include', type: 'string', default: '', description: 'You may specify relations to include with your response. Choices: open, closed, killed', - }, - { + }, + { displayName: 'Order', name: 'order', type: 'string', @@ -390,7 +390,7 @@ export class Disqus implements INodeType { description: 'You may specify order to sort your response.Choices: asc, desc', }, ], - } + } ], }; @@ -415,7 +415,7 @@ export class Disqus implements INodeType { for (let i = 0; i < items.length; i++) { - body = {}; + body = {}; qs = {}; if (resource === 'forum') { @@ -426,10 +426,10 @@ export class Disqus implements INodeType { requestMethod = 'GET'; - endpoint = 'forums/details.json'; + endpoint = 'forums/details.json'; - const id = this.getNodeParameter('id', i) as string; - qs.forum = id; + const id = this.getNodeParameter('id', i) as string; + qs.forum = id; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; @@ -442,10 +442,10 @@ export class Disqus implements INodeType { requestMethod = 'GET'; - endpoint = 'forums/listPosts.json'; + endpoint = 'forums/listPosts.json'; - const id = this.getNodeParameter('id', i) as string; - qs.forum = id; + const id = this.getNodeParameter('id', i) as string; + qs.forum = id; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; @@ -458,10 +458,10 @@ export class Disqus implements INodeType { requestMethod = 'GET'; - endpoint = 'forums/listCategories.json'; + endpoint = 'forums/listCategories.json'; - const id = this.getNodeParameter('id', i) as string; - qs.forum = id; + const id = this.getNodeParameter('id', i) as string; + qs.forum = id; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; @@ -474,10 +474,10 @@ export class Disqus implements INodeType { requestMethod = 'GET'; - endpoint = 'forums/listThreads.json'; + endpoint = 'forums/listThreads.json'; - const id = this.getNodeParameter('id', i) as string; - qs.forum = id; + const id = this.getNodeParameter('id', i) as string; + qs.forum = id; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; @@ -485,14 +485,14 @@ export class Disqus implements INodeType { } else { throw new Error(`The operation "${operation}" is not known!`); - } + } } else { throw new Error(`The resource "${resource}" is not known!`); } - qs.api_key = credentials.accessToken; - endpoint = `https://disqus.com/api/3.0/${endpoint}`; + qs.api_key = credentials.accessToken; + endpoint = `https://disqus.com/api/3.0/${endpoint}`; const options: OptionsWithUri = { method: requestMethod, @@ -527,6 +527,6 @@ export class Disqus implements INodeType { } } - return [this.helpers.returnJsonArray(returnData)]; + return [this.helpers.returnJsonArray(returnData)]; } } From 23e844398b8371094a1a981bae4eb1548e504c0a Mon Sep 17 00:00:00 2001 From: trojanh Date: Thu, 23 Jan 2020 20:43:57 +0530 Subject: [PATCH 5/5] Add returnAll and refactoring --- .../nodes-base/nodes/Disqus/Disqus.node.ts | 233 ++++++++++++++---- .../nodes/Disqus/GenericFunctions.ts | 87 +++++++ 2 files changed, 273 insertions(+), 47 deletions(-) create mode 100644 packages/nodes-base/nodes/Disqus/GenericFunctions.ts diff --git a/packages/nodes-base/nodes/Disqus/Disqus.node.ts b/packages/nodes-base/nodes/Disqus/Disqus.node.ts index 85eb133def..213da8ef4b 100644 --- a/packages/nodes-base/nodes/Disqus/Disqus.node.ts +++ b/packages/nodes-base/nodes/Disqus/Disqus.node.ts @@ -9,7 +9,7 @@ import { INodeType, } from 'n8n-workflow'; -import { OptionsWithUri } from 'request'; +import { disqusApiRequest, disqusApiRequestAllItems } from './GenericFunctions'; export class Disqus implements INodeType { @@ -164,6 +164,47 @@ export class Disqus implements INodeType { }, description: 'The short name(aka ID) of the forum to get.', }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'forum', + ], + operation: [ + 'getPosts', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'forum', + ], + operation: [ + 'getPosts', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 100, + description: 'How many results to return.', + }, { displayName: 'Additional Fields', name: 'additionalFields', @@ -261,6 +302,47 @@ export class Disqus implements INodeType { }, description: 'The short name(aka ID) of the forum to get Categories.', }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'forum', + ], + operation: [ + 'getCategories', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'forum', + ], + operation: [ + 'getCategories', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 100, + description: 'How many results to return.', + }, { displayName: 'Additional Fields', name: 'additionalFields', @@ -323,6 +405,47 @@ export class Disqus implements INodeType { }, description: 'The short name(aka ID) of the forum to get Threads.', }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'forum', + ], + operation: [ + 'getThreads', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'forum', + ], + operation: [ + 'getThreads', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 100, + description: 'How many results to return.', + }, { displayName: 'Additional Fields', name: 'additionalFields', @@ -399,11 +522,6 @@ export class Disqus implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; - const credentials = this.getCredentials('disqusApi'); - - if (credentials === undefined) { - throw new Error('No credentials got returned!'); - } const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; @@ -435,6 +553,13 @@ export class Disqus implements INodeType { Object.assign(qs, additionalFields); + try { + const responseData = await disqusApiRequest.call(this, requestMethod, qs, endpoint); + returnData.push(responseData.response); + } catch (error) { + throw error; + } + } else if (operation === 'getPosts') { // ---------------------------------- // getPosts @@ -445,12 +570,28 @@ export class Disqus implements INodeType { endpoint = 'forums/listPosts.json'; const id = this.getNodeParameter('id', i) as string; - qs.forum = id; - const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; - Object.assign(qs, additionalFields); + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + + qs.forum = id; + qs.limit = 100; + + try { + let responseData: IDataObject = {}; + if(returnAll) { + responseData.response = await disqusApiRequestAllItems.call(this, requestMethod, qs, endpoint); + } else { + const limit = this.getNodeParameter('limit', i) as string; + qs.limit = limit; + responseData = await disqusApiRequest.call(this, requestMethod, qs, endpoint); + } + returnData.push.apply(returnData, responseData.response as IDataObject[]); + } catch (error) { + throw error; + } + } else if (operation === 'getCategories') { // ---------------------------------- // getCategories @@ -461,12 +602,28 @@ export class Disqus implements INodeType { endpoint = 'forums/listCategories.json'; const id = this.getNodeParameter('id', i) as string; - qs.forum = id; - + const returnAll = this.getNodeParameter('returnAll', i) as boolean; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; - Object.assign(qs, additionalFields); + qs.forum = id; + qs.limit = 100; + + try { + let responseData: IDataObject = {}; + + if(returnAll) { + responseData.response = await disqusApiRequestAllItems.call(this, requestMethod, qs, endpoint); + } else { + const limit = this.getNodeParameter('limit', i) as string; + qs.limit = limit; + responseData = await disqusApiRequest.call(this, requestMethod, qs, endpoint) as IDataObject; + } + returnData.push.apply(returnData, responseData.response as IDataObject[]) ; + } catch (error) { + throw error; + } + } else if (operation === 'getThreads') { // ---------------------------------- // getThreads @@ -477,12 +634,29 @@ export class Disqus implements INodeType { endpoint = 'forums/listThreads.json'; const id = this.getNodeParameter('id', i) as string; + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + qs.forum = id; + qs.limit = 100; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; Object.assign(qs, additionalFields); + try { + let responseData: IDataObject = {}; + if(returnAll) { + responseData.response = await disqusApiRequestAllItems.call(this, requestMethod, qs, endpoint); + } else { + const limit = this.getNodeParameter('limit', i) as string; + qs.limit = limit; + responseData = await disqusApiRequest.call(this, requestMethod, qs, endpoint); + } + returnData.push.apply(returnData, responseData.response as IDataObject[]); + } catch (error) { + throw error; + } + } else { throw new Error(`The operation "${operation}" is not known!`); } @@ -490,41 +664,6 @@ export class Disqus implements INodeType { } else { throw new Error(`The resource "${resource}" is not known!`); } - - qs.api_key = credentials.accessToken; - endpoint = `https://disqus.com/api/3.0/${endpoint}`; - - const options: OptionsWithUri = { - method: requestMethod, - qs, - uri: endpoint, - json: true, - }; - - - let responseData; - try { - responseData = await this.helpers.request(options); - } catch (error) { - if (error.statusCode === 401) { - // Return a clear error - throw new Error('The Disqus credentials are not valid!'); - } - - if (error.error && error.error.error_summary) { - // Try to return the error prettier - throw new Error(`Disqus error response [${error.statusCode}]: ${error.error.error_summary}`); - } - - // If that data does not exist for some reason return the actual error - throw error; - } - - if (responseData && Array.isArray(responseData)) { - returnData.push.apply(returnData, responseData as IDataObject[]); - } else { - returnData.push(responseData as IDataObject); - } } return [this.helpers.returnJsonArray(returnData)]; diff --git a/packages/nodes-base/nodes/Disqus/GenericFunctions.ts b/packages/nodes-base/nodes/Disqus/GenericFunctions.ts new file mode 100644 index 0000000000..e5e5c1b7df --- /dev/null +++ b/packages/nodes-base/nodes/Disqus/GenericFunctions.ts @@ -0,0 +1,87 @@ +import { OptionsWithUri } from 'request'; +import { + IExecuteFunctions, + IExecuteSingleFunctions, + IHookFunctions, + ILoadOptionsFunctions, +} from 'n8n-core'; +import { IDataObject } from 'n8n-workflow'; + +export async function disqusApiRequest( + this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, + method: string, + qs: IDataObject = {}, + uri?: string, + body: any = {}, + option: IDataObject = {} + ): Promise { // tslint:disable-line:no-any + + const credentials = this.getCredentials('disqusApi') as IDataObject; + qs.api_key = credentials.accessToken; + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + let options: OptionsWithUri = { + method, + qs, + body, + uri: `https://disqus.com/api/3.0/${uri}`, + json: true + }; + + options = Object.assign({}, options, option); + if (Object.keys(options.body).length === 0) { + delete options.body; + } + try { + const result = await this.helpers.request!(options) + return result; + } catch (error) { + console.log(error) + if (error.statusCode === 401) { + // Return a clear error + throw new Error('The Disqus credentials are not valid!'); + } + + if (error.error && error.error.error_summary) { + // Try to return the error prettier + throw new Error(`Disqus error response [${error.statusCode}]: ${error.error.error_summary}`); + } + + // If that data does not exist for some reason return the actual error + throw error; + } +} + +/** + * Make an API request to paginated flow endpoint + * and return all results + */ +export async function disqusApiRequestAllItems( + this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, + method: string, + qs: IDataObject = {}, + uri?: string, + body: any = {}, + option: IDataObject = {} + ): Promise { // tslint:disable-line:no-any + + const returnData: IDataObject[] = []; + + let responseData; + + try { + do { + responseData = await disqusApiRequest.call(this, method, qs, uri, body, option); + qs.cursor = responseData.cursor.id; + returnData.push.apply(returnData, responseData.response); + } while ( + responseData.cursor.more === true && + responseData.cursor.hasNext === true + ); + return returnData; + } catch(error) { + throw error; + } +}