diff --git a/packages/nodes-base/credentials/JiraApi.credentials.ts b/packages/nodes-base/credentials/JiraApi.credentials.ts new file mode 100644 index 0000000000..ddb1996454 --- /dev/null +++ b/packages/nodes-base/credentials/JiraApi.credentials.ts @@ -0,0 +1,18 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + + +export class JiraApi implements ICredentialType { + name = 'jiraApi'; + displayName = 'Jira API'; + properties = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Jira/GenericFunctions.ts b/packages/nodes-base/nodes/Jira/GenericFunctions.ts new file mode 100644 index 0000000000..f52062f8ae --- /dev/null +++ b/packages/nodes-base/nodes/Jira/GenericFunctions.ts @@ -0,0 +1,82 @@ +import { OptionsWithUri } from 'request'; + +import { + IExecuteFunctions, + IHookFunctions, + ILoadOptionsFunctions, + IExecuteSingleFunctions +} from 'n8n-core'; + +import { + IDataObject, +} from 'n8n-workflow'; + +export async function jiraApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, endpoint: string, method: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any + const credentials = this.getCredentials('jiraApi'); + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + const headerWithAuthentication = Object.assign({}, + { Authorization: `Bearer ${credentials.apiKey}`, Accept: 'application/json' }); + + const options: OptionsWithUri = { + headers: headerWithAuthentication, + method, + qs: query, + uri: uri || `https://api.intercom.io${endpoint}`, + body, + json: true + }; + + try { + return await this.helpers.request!(options); + } catch (error) { + const errorMessage = error.response.body.message || error.response.body.Message; + + if (errorMessage !== undefined) { + throw errorMessage; + } + throw error.response.body; + } +} + + + +/** + * Make an API request to paginated intercom endpoint + * and return all results + */ +export async function jiraApiRequestAllItems(this: IHookFunctions | IExecuteFunctions, propertyName: string, endpoint: string, method: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any + + const returnData: IDataObject[] = []; + + let responseData; + + query.per_page = 60; + + let uri: string | undefined; + + do { + responseData = await jiraApiRequest.call(this, endpoint, method, body, query, uri); + uri = responseData.pages.next; + returnData.push.apply(returnData, responseData[propertyName]); + } while ( + responseData.pages !== undefined && + responseData.pages.next !== undefined && + responseData.pages.next !== null + ); + + return returnData; +} + + +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/Jira/Jira.node.ts b/packages/nodes-base/nodes/Jira/Jira.node.ts new file mode 100644 index 0000000000..df38733e83 --- /dev/null +++ b/packages/nodes-base/nodes/Jira/Jira.node.ts @@ -0,0 +1,60 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; +import { + IDataObject, + INodeTypeDescription, + INodeExecutionData, + INodeType, + ILoadOptionsFunctions, + INodePropertyOptions, +} from 'n8n-workflow'; +import { + jiraApiRequest, + jiraApiRequestAllItems, + validateJSON, +} from './GenericFunctions'; + +export class Jira implements INodeType { + description: INodeTypeDescription = { + displayName: 'Jira', + name: 'Jira', + icon: 'file:jira.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume Jira API', + defaults: { + name: 'Jira', + color: '#c02428', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'jiraApi', + required: true, + } + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Issue', + value: 'issue', + description: 'Creates an issue or, where the option to create subtasks is enabled in Jira, a subtask', + }, + ], + default: 'issue', + description: 'Resource to consume.', + }, + ], + }; + + async execute(this: IExecuteFunctions): Promise { + return [this.helpers.returnJsonArray({})]; + } +} diff --git a/packages/nodes-base/nodes/Jira/jira.png b/packages/nodes-base/nodes/Jira/jira.png new file mode 100644 index 0000000000..665ee5a217 Binary files /dev/null and b/packages/nodes-base/nodes/Jira/jira.png differ diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index ae70262dc8..6673d95d77 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -42,7 +42,8 @@ "dist/credentials/HttpDigestAuth.credentials.js", "dist/credentials/HttpHeaderAuth.credentials.js", "dist/credentials/IntercomApi.credentials.js", - "dist/credentials/Imap.credentials.js", + "dist/credentials/Imap.credentials.js", + "dist/credentials/JiraApi.credentials.js", "dist/credentials/LinkFishApi.credentials.js", "dist/credentials/MailchimpApi.credentials.js", "dist/credentials/MailgunApi.credentials.js", @@ -100,7 +101,8 @@ "dist/nodes/HttpRequest.node.js", "dist/nodes/If.node.js", "dist/nodes/Interval.node.js", - "dist/nodes/Intercom/Intercom.node.js", + "dist/nodes/Intercom/Intercom.node.js", + "dist/nodes/Jira/Jira.node.js", "dist/nodes/LinkFish/LinkFish.node.js", "dist/nodes/Mailchimp/Mailchimp.node.js", "dist/nodes/Mailgun/Mailgun.node.js",