Merge pull request 'joel-plutio' (#1) from joel-plutio into master
Reviewed-on: #1
This commit is contained in:
commit
dad641b8bc
|
@ -0,0 +1,17 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[package.json]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.yml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
|
@ -0,0 +1,51 @@
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es6: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
project: ['./tsconfig.json'],
|
||||||
|
sourceType: 'module',
|
||||||
|
extraFileExtensions: ['.json'],
|
||||||
|
},
|
||||||
|
ignorePatterns: [
|
||||||
|
'.eslintrc.js',
|
||||||
|
'**/*.js',
|
||||||
|
'**/node_modules/**',
|
||||||
|
'**/dist/**',
|
||||||
|
],
|
||||||
|
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['package.json'],
|
||||||
|
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||||
|
extends: ['plugin:n8n-nodes-base/community'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['./credentials/**/*.ts'],
|
||||||
|
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||||
|
extends: ['plugin:n8n-nodes-base/credentials'],
|
||||||
|
rules: {
|
||||||
|
'n8n-nodes-base/cred-class-field-documentation-url-missing': 'off',
|
||||||
|
'n8n-nodes-base/cred-class-field-documentation-url-miscased': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['./nodes/**/*.ts'],
|
||||||
|
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||||
|
extends: ['plugin:n8n-nodes-base/nodes'],
|
||||||
|
rules: {
|
||||||
|
'n8n-nodes-base/node-execute-block-missing-continue-on-fail': 'off',
|
||||||
|
'n8n-nodes-base/node-resource-description-filename-against-convention': 'off',
|
||||||
|
'n8n-nodes-base/node-param-fixed-collection-type-unsorted-items': 'off',
|
||||||
|
'n8n-nodes-base/node-execute-block-operation-missing-singular-pairing': 'off',
|
||||||
|
'n8n-nodes-base/node-execute-block-operation-missing-plural-pairing': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -1,120 +1,8 @@
|
||||||
# ---> Node
|
node_modules
|
||||||
# Logs
|
.DS_Store
|
||||||
logs
|
.tmp
|
||||||
*.log
|
tmp
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
.pnpm-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# Snowpack dependency directory (https://snowpack.dev/)
|
|
||||||
web_modules/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variables file
|
|
||||||
.env
|
|
||||||
.env.test
|
|
||||||
.env.production
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
.parcel-cache
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
out
|
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
|
||||||
.nuxt
|
|
||||||
dist
|
dist
|
||||||
|
npm-debug.log*
|
||||||
# Gatsby files
|
yarn.lock
|
||||||
.cache/
|
.vscode/launch.json
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
# Stores VSCode versions used for testing VSCode extensions
|
|
||||||
.vscode-test
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/cache
|
|
||||||
.yarn/unplugged
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#semicolons
|
||||||
|
*/
|
||||||
|
semi: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#trailing-commas
|
||||||
|
*/
|
||||||
|
trailingComma: 'all',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#bracket-spacing
|
||||||
|
*/
|
||||||
|
bracketSpacing: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#tabs
|
||||||
|
*/
|
||||||
|
useTabs: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#tab-width
|
||||||
|
*/
|
||||||
|
tabWidth: 2,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#arrow-function-parentheses
|
||||||
|
*/
|
||||||
|
arrowParens: 'always',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#quotes
|
||||||
|
*/
|
||||||
|
singleQuote: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#quote-props
|
||||||
|
*/
|
||||||
|
quoteProps: 'as-needed',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#end-of-line
|
||||||
|
*/
|
||||||
|
endOfLine: 'lf',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#print-width
|
||||||
|
*/
|
||||||
|
printWidth: 100,
|
||||||
|
};
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"EditorConfig.EditorConfig",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
]
|
||||||
|
}
|
32
README.md
32
README.md
|
@ -4,9 +4,33 @@ This repo contains the N8N Plutio node created by Chykalophia.
|
||||||
We created this N8N module so that we could internet our internal tools together. This module connects via the Plutio API to manage:
|
We created this N8N module so that we could internet our internal tools together. This module connects via the Plutio API to manage:
|
||||||
|
|
||||||
- Tasks
|
- Tasks
|
||||||
|
- Get (single) Task
|
||||||
|
- Delete Task
|
||||||
|
- Update Task
|
||||||
|
- Create Task
|
||||||
|
- Copy Task
|
||||||
|
- Move Task
|
||||||
- Projects
|
- Projects
|
||||||
|
- Create Project
|
||||||
|
- Get (single) Project
|
||||||
|
- By user email
|
||||||
|
- By user ID
|
||||||
|
- By Project name
|
||||||
|
- By Project ID
|
||||||
|
- Update Project
|
||||||
|
- Delete Project
|
||||||
- Comments
|
- Comments
|
||||||
|
- Create Comment
|
||||||
|
- Get (single) Comment
|
||||||
|
- Update Comment
|
||||||
|
- Delete Comment
|
||||||
- Invoices
|
- Invoices
|
||||||
|
- Create Invoice
|
||||||
|
- Get (single) Invoice
|
||||||
|
- Update Invoice
|
||||||
|
- Delete Invoice
|
||||||
|
|
||||||
|
This module uses Plutio API version 1.10
|
||||||
|
|
||||||
# About Chykalophia
|
# About Chykalophia
|
||||||
|
|
||||||
|
@ -18,8 +42,12 @@ We are a team of dedicated nerds and creatived working with women-led brands to
|
||||||
|
|
||||||
## Using this Custom node & Installtion
|
## Using this Custom node & Installtion
|
||||||
|
|
||||||
Run `npm i n8n-nodes-plutio` from inside the docker container or your n8n folder for modules.
|
Update N8N to version 0.193.5 or higher.
|
||||||
|
|
||||||
|
Go to N8N Settings -> Community nodes -> Install a community node -> write `n8n-nodes-plutio`
|
||||||
|
|
||||||
|
Note: You need to have owner/administrator privilege to install community node.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT](https://github.com/n8n-io/n8n-nodes-starter/blob/master/LICENSE.md)
|
[MIT](https://github.com/n8n-io/n8n-nodes-starter/blob/master/LICENSE.md)
|
||||||
|
|
|
@ -1,12 +1,43 @@
|
||||||
import {
|
import {
|
||||||
ICredentialType,
|
ICredentialType,
|
||||||
INodeProperties,
|
INodeProperties,
|
||||||
|
ICredentialDataDecryptedObject,
|
||||||
|
IAuthenticateGeneric,
|
||||||
|
IExecuteFunctions,
|
||||||
|
ICredentialTestRequest,
|
||||||
|
NodeApiError,
|
||||||
|
IDataObject,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
export class PlutioApi implements ICredentialType {
|
export class PlutioApi implements ICredentialType {
|
||||||
name = 'plutioApi';
|
name = 'plutioApi';
|
||||||
displayName = 'Plutio API';
|
displayName = 'Plutio API';
|
||||||
|
extends = ['oAuth2Api'];
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
|
// {
|
||||||
|
// displayName: 'Grant Type',
|
||||||
|
// name: 'grantType',
|
||||||
|
// type: 'hidden',
|
||||||
|
// default: 'client_credentials',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// displayName: 'Scope',
|
||||||
|
// name: 'scope',
|
||||||
|
// type: 'hidden',
|
||||||
|
// default: '*',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// displayName: 'Authentication',
|
||||||
|
// name: 'authentication',
|
||||||
|
// type: 'hidden',
|
||||||
|
// default: 'header',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// displayName: 'Access Token URL',
|
||||||
|
// name: 'accessTokenUrl',
|
||||||
|
// type: 'hidden',
|
||||||
|
// default: 'https://api.plutio.com/v1.10/oauth/token',
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
displayName: 'Client ID',
|
displayName: 'Client ID',
|
||||||
name: 'clientId',
|
name: 'clientId',
|
||||||
|
@ -29,4 +60,57 @@ export class PlutioApi implements ICredentialType {
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// async preAuthentication(this: IExecuteFunctions, credentials: ICredentialDataDecryptedObject) {
|
||||||
|
// const endpoint = 'api.plutio.com/v1.10';
|
||||||
|
// const returnData: IDataObject[] = [];
|
||||||
|
// let access_token;
|
||||||
|
// try {
|
||||||
|
// access_token = await this.helpers.httpRequest({
|
||||||
|
// method: 'POST',
|
||||||
|
// url: `https://${endpoint}/oauth/token`,
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
// 'business': `${credentials.business}`,
|
||||||
|
// },
|
||||||
|
// body: {
|
||||||
|
// 'client_id': `${credentials.clientId}`,
|
||||||
|
// 'client_secret': `${credentials.clientSecret}`,
|
||||||
|
// 'grant_type': 'client_credentials',
|
||||||
|
// },
|
||||||
|
// json: true,
|
||||||
|
// }) as {access_token: IDataObject};
|
||||||
|
// if (Array.isArray(access_token)) {
|
||||||
|
// returnData.push.apply(returnData, access_token as IDataObject[]);
|
||||||
|
// } else {
|
||||||
|
// if (access_token === undefined) {
|
||||||
|
// access_token = {
|
||||||
|
// success: true,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// returnData.push(access_token as IDataObject);
|
||||||
|
// }
|
||||||
|
// if (returnData[0].accessToken) {
|
||||||
|
// return {accessToken: returnData[0].accessToken};
|
||||||
|
// }
|
||||||
|
// } catch (error) {
|
||||||
|
// throw new NodeApiError(this.getNode(), error);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// authenticate: IAuthenticateGeneric = {
|
||||||
|
// type: 'generic',
|
||||||
|
// properties: {
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/json',
|
||||||
|
// 'Business': '={{$credentials.business}}',
|
||||||
|
// 'Authorization': '=Bearer {{$credentials.accessToken}}',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
// test: ICredentialTestRequest = {
|
||||||
|
// request: {
|
||||||
|
// baseURL: 'https://api.plutio.com/v1.10',
|
||||||
|
// url: '/templates',
|
||||||
|
// },
|
||||||
|
// };
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,11 @@ async function plutioApiRequestToken(this: IExecuteFunctions | ILoadOptionsFunct
|
||||||
const clientId = `${credentials.clientId}`;
|
const clientId = `${credentials.clientId}`;
|
||||||
const clientSecret = `${credentials.clientSecret}`;
|
const clientSecret = `${credentials.clientSecret}`;
|
||||||
const business = `${credentials.business}`;
|
const business = `${credentials.business}`;
|
||||||
|
<<<<<<< HEAD
|
||||||
|
const endpoint = 'api.plutio.com/v1.10';
|
||||||
|
=======
|
||||||
const endpoint = 'api.plutio.com/v1.9';
|
const endpoint = 'api.plutio.com/v1.9';
|
||||||
|
>>>>>>> master
|
||||||
const returnData: IDataObject[] = [];
|
const returnData: IDataObject[] = [];
|
||||||
|
|
||||||
let responseData;
|
let responseData;
|
||||||
|
@ -58,7 +62,11 @@ async function plutioApiRequestToken(this: IExecuteFunctions | ILoadOptionsFunct
|
||||||
|
|
||||||
// Rest API function for plutio node.
|
// Rest API function for plutio node.
|
||||||
export async function plutioApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
export async function plutioApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||||
|
<<<<<<< HEAD
|
||||||
|
const endpoint = 'api.plutio.com/v1.10';
|
||||||
|
=======
|
||||||
const endpoint = 'api.plutio.com/v1.9';
|
const endpoint = 'api.plutio.com/v1.9';
|
||||||
|
>>>>>>> master
|
||||||
const credentials = await this.getCredentials('plutioApi');
|
const credentials = await this.getCredentials('plutioApi');
|
||||||
const plutioApiToken = await plutioApiRequestToken.call(this);
|
const plutioApiToken = await plutioApiRequestToken.call(this);
|
||||||
const business = `${credentials.business}`;
|
const business = `${credentials.business}`;
|
||||||
|
|
|
@ -50,6 +50,7 @@ interface ICreatePlutioBody {
|
||||||
currency?: string;
|
currency?: string;
|
||||||
discount?: string;
|
discount?: string;
|
||||||
index?: number;
|
index?: number;
|
||||||
|
contributors?: [string];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Plutio implements INodeType {
|
export class Plutio implements INodeType {
|
||||||
|
@ -93,7 +94,7 @@ export class Plutio implements INodeType {
|
||||||
value: 'invoice',
|
value: 'invoice',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Project-CKLPH',
|
name: 'Project',
|
||||||
value: 'project',
|
value: 'project',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -208,6 +209,21 @@ export class Plutio implements INodeType {
|
||||||
return returnData;
|
return returnData;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async getProjectTemplateId(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
|
const returnData: INodePropertyOptions[] = [];
|
||||||
|
const ids = await plutioApiRequest.call(this, 'GET', '/templates', {}, {'entityType': 'project'});
|
||||||
|
for (const id of ids) {
|
||||||
|
const templateName = id.title;
|
||||||
|
const templateId = id._id;
|
||||||
|
|
||||||
|
returnData.push({
|
||||||
|
name: templateName,
|
||||||
|
value: templateId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return returnData;
|
||||||
|
},
|
||||||
|
|
||||||
async getProjectId(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
async getProjectId(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
const returnData: INodePropertyOptions[] = [];
|
const returnData: INodePropertyOptions[] = [];
|
||||||
const ids = await plutioApiRequest.call(this, 'GET', '/projects');
|
const ids = await plutioApiRequest.call(this, 'GET', '/projects');
|
||||||
|
@ -227,7 +243,7 @@ export class Plutio implements INodeType {
|
||||||
// select them easily
|
// select them easily
|
||||||
async getCustomFieldTitle(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
async getCustomFieldTitle(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
const returnData: INodePropertyOptions[] = [];
|
const returnData: INodePropertyOptions[] = [];
|
||||||
const fields = await plutioApiRequest.call(this, 'GET', '/custom-fields');
|
const fields = await plutioApiRequest.call(this, 'GET', '/custom-fields', {}, {'entityType': 'task'});
|
||||||
for (const field of fields) {
|
for (const field of fields) {
|
||||||
if ('task' === field.entityType) {
|
if ('task' === field.entityType) {
|
||||||
const fieldName = field.title;
|
const fieldName = field.title;
|
||||||
|
@ -241,6 +257,21 @@ export class Plutio implements INodeType {
|
||||||
}
|
}
|
||||||
return returnData;
|
return returnData;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async getProjectCustomField(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
|
const returnData: INodePropertyOptions[] = [];
|
||||||
|
const fields = await plutioApiRequest.call(this, 'GET', '/custom-fields', {}, {'entityType': 'project'});
|
||||||
|
for (const field of fields) {
|
||||||
|
const fieldName = field.title;
|
||||||
|
const fieldValue = field._id;
|
||||||
|
|
||||||
|
returnData.push({
|
||||||
|
name: fieldName,
|
||||||
|
value: fieldValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return returnData;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -326,20 +357,22 @@ export class Plutio implements INodeType {
|
||||||
}
|
}
|
||||||
if (options.customFields) {
|
if (options.customFields) {
|
||||||
const metadata = (options.customFields as IDataObject).customField as IDataObject[];
|
const metadata = (options.customFields as IDataObject).customField as IDataObject[];
|
||||||
const customQs = {"$or":[{"inputType": "select"}, {"inputType": "multi"}],"entityType":"task"};
|
if (metadata) {
|
||||||
await plutioApiRequest.call(this, 'GET', '/custom-fields', {}, customQs).then(responses => {
|
const customQs = {"$or":[{"inputType": "select"}, {"inputType": "multi"}],"entityType":"task"};
|
||||||
for (const data of metadata) {
|
await plutioApiRequest.call(this, 'GET', '/custom-fields', {}, customQs).then(responses => {
|
||||||
for (const response of responses) {
|
for (const data of metadata) {
|
||||||
if (response._id === data._id) {
|
for (const response of responses) {
|
||||||
for (const option of response.options) {
|
if (response._id === data._id) {
|
||||||
if (option.name === data.value) {
|
for (const option of response.options) {
|
||||||
data.value = (option.name as string).replace(/^[(a-zA-Z\s)]*$/g, option._id);
|
if (option.name === data.value) {
|
||||||
|
data.value = (option.name as string).replace(/^[(a-zA-Z\s)]*$/g, option._id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
body.customFields = metadata;
|
body.customFields = metadata;
|
||||||
delete options.customFields;
|
delete options.customFields;
|
||||||
}
|
}
|
||||||
|
@ -813,6 +846,159 @@ export class Plutio implements INodeType {
|
||||||
responseData = {'name': 'default'};
|
responseData = {'name': 'default'};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ('get' === operation) {
|
||||||
|
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||||
|
|
||||||
|
if (options.contributor) {
|
||||||
|
let contributorId;
|
||||||
|
const users = await plutioApiRequest.call(this, 'GET', '/people');
|
||||||
|
for (const user of users) {
|
||||||
|
if (user.contactEmails[0].address === options.contributor || options.contributor === user._id) {
|
||||||
|
contributorId = user._id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qs.contributors = contributorId as string;
|
||||||
|
}
|
||||||
|
if (options._id) {
|
||||||
|
qs._id = options._id as string;
|
||||||
|
}
|
||||||
|
responseData = await plutioApiRequest.call(this, 'GET', '/projects', {}, qs);
|
||||||
|
}
|
||||||
|
if ('create' === operation) {
|
||||||
|
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||||
|
const customFields = this.getNodeParameter('customFields', i) as IDataObject;
|
||||||
|
const contributors = this.getNodeParameter('contributorsUi', i) as IDataObject;
|
||||||
|
|
||||||
|
if (options.name) {
|
||||||
|
body.name = options.name as string;
|
||||||
|
}
|
||||||
|
if (options.templateId) {
|
||||||
|
body.templateId = options.templateId as string;
|
||||||
|
}
|
||||||
|
if (customFields) {
|
||||||
|
const metadata = (customFields as IDataObject).customField as IDataObject[];
|
||||||
|
if (metadata) {
|
||||||
|
const customQs = {"$or":[{"inputType": "select"}, {"inputType": "multi"}],"entityType":"project"};
|
||||||
|
await plutioApiRequest.call(this, 'GET', '/custom-fields', {}, customQs).then(responses => {
|
||||||
|
for (const data of metadata) {
|
||||||
|
for (const response of responses) {
|
||||||
|
if (response._id === data._id) {
|
||||||
|
for (const option of response.options) {
|
||||||
|
if (option.name === data.value) {
|
||||||
|
data.value = (option.name as string).replace(/^[(a-zA-Z\s)]*$/g, option._id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
body.customFields = metadata as IDataObject[];
|
||||||
|
}
|
||||||
|
if (contributors) {
|
||||||
|
const metadata = (contributors as IDataObject).contributors as IDataObject[];
|
||||||
|
let contributor: IProperyId[] = [];
|
||||||
|
const users: IProperyId[] = [];
|
||||||
|
|
||||||
|
if (metadata) {
|
||||||
|
for (const data of metadata) {
|
||||||
|
contributor.push(data.value as IDataObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// flatten contributor array.
|
||||||
|
contributor = contributor.flatMap(a => a);
|
||||||
|
const customQs = {'status': 'active'};
|
||||||
|
|
||||||
|
await plutioApiRequest.call(this, 'GET', '/people', {}, customQs).then(people => {
|
||||||
|
for (const id of contributor) {
|
||||||
|
for (const person of people) {
|
||||||
|
const userName = (person.name.last) ? `${person.name.first} ${person.name.last}` : `${person.name.first}`;
|
||||||
|
if (id === person._id || id === userName) {
|
||||||
|
users.push(person._id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove duplicates.
|
||||||
|
contributor = users.filter((c, index) => {
|
||||||
|
return users.indexOf(c) === index;
|
||||||
|
});
|
||||||
|
|
||||||
|
body.contributors = contributor as [string];
|
||||||
|
}
|
||||||
|
responseData = await plutioApiRequest.call(this, 'POST', '/projects', body);
|
||||||
|
}
|
||||||
|
if ('update' === operation) {
|
||||||
|
const _id = this.getNodeParameter('_id', 0) as string;
|
||||||
|
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||||
|
const customFields = this.getNodeParameter('customFields', i) as IDataObject;
|
||||||
|
const contributors = this.getNodeParameter('contributorsUi', i) as IDataObject;
|
||||||
|
|
||||||
|
if (_id) {
|
||||||
|
body._id = _id as string;
|
||||||
|
}
|
||||||
|
if (options.name) {
|
||||||
|
body.name = options.name as string;
|
||||||
|
}
|
||||||
|
if (options.templateId) {
|
||||||
|
body.templateId = options.templateId as string;
|
||||||
|
}
|
||||||
|
if (customFields) {
|
||||||
|
const metadata = (customFields as IDataObject).customField as IDataObject[];
|
||||||
|
if (metadata) {
|
||||||
|
const customQs = {"$or":[{"inputType": "select"}, {"inputType": "multi"}],"entityType":"project"};
|
||||||
|
await plutioApiRequest.call(this, 'GET', '/custom-fields', {}, customQs).then(responses => {
|
||||||
|
for (const data of metadata) {
|
||||||
|
for (const response of responses) {
|
||||||
|
if (response._id === data._id) {
|
||||||
|
for (const option of response.options) {
|
||||||
|
if (option.name === data.value) {
|
||||||
|
data.value = (option.name as string).replace(/^[(a-zA-Z\s)]*$/g, option._id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
body.customFields = metadata as IDataObject[];
|
||||||
|
}
|
||||||
|
if (contributors) {
|
||||||
|
const metadata = (contributors as IDataObject).contributors as IDataObject[];
|
||||||
|
let contributor: IProperyId[] = [];
|
||||||
|
const users: IProperyId[] = [];
|
||||||
|
if (metadata) {
|
||||||
|
for (const data of metadata) {
|
||||||
|
contributor.push(data.value as IDataObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// flatten contributor array.
|
||||||
|
contributor = contributor.flatMap(a => a);
|
||||||
|
const customQs = {'status': 'active'};
|
||||||
|
|
||||||
|
await plutioApiRequest.call(this, 'GET', '/people', {}, customQs).then(people => {
|
||||||
|
for (const id of contributor) {
|
||||||
|
for (const person of people) {
|
||||||
|
const userName = (person.name.last) ? `${person.name.first} ${person.name.last}` : `${person.name.first}`;
|
||||||
|
if (id === person._id || id === userName) {
|
||||||
|
users.push(person._id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove duplicates.
|
||||||
|
contributor = users.filter((c, index) => {
|
||||||
|
return users.indexOf(c) === index;
|
||||||
|
});
|
||||||
|
|
||||||
|
body.contributors = contributor as [string];
|
||||||
|
}
|
||||||
|
responseData = await plutioApiRequest.call(this, 'PUT', '/projects', body);;
|
||||||
|
}
|
||||||
if ('move' === operation) {
|
if ('move' === operation) {
|
||||||
const _id = this.getNodeParameter('_id', 0) as string;
|
const _id = this.getNodeParameter('_id', 0) as string;
|
||||||
const index = this.getNodeParameter('index', 0) as number;
|
const index = this.getNodeParameter('index', 0) as number;
|
||||||
|
|
|
@ -41,12 +41,12 @@ export const projectOperations: INodeProperties[] = [
|
||||||
description: 'Get projects',
|
description: 'Get projects',
|
||||||
action: 'Get a project',
|
action: 'Get a project',
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
name: 'Get CKLPH',
|
// name: 'Chykalophia',
|
||||||
value: 'getCklph',
|
// value: 'getCklph',
|
||||||
description: 'Get projects by contributor\'s email for CKLPH',
|
// description: 'Get projects by contributor\'s email for CKLPH',
|
||||||
action: 'Get a project',
|
// action: 'Get a project',
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
name: 'Move',
|
name: 'Move',
|
||||||
value: 'move',
|
value: 'move',
|
||||||
|
@ -85,6 +85,130 @@ export const projectDescription: INodeProperties[] = [
|
||||||
},
|
},
|
||||||
description: 'ID of Project',
|
description: 'ID of Project',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Options',
|
||||||
|
name: 'options',
|
||||||
|
type: 'collection',
|
||||||
|
placeholder: 'Add Option',
|
||||||
|
default: {},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'project',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'update',
|
||||||
|
'create',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Project Name',
|
||||||
|
name: 'name',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'Name of Project',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Template Name or ID',
|
||||||
|
name: 'templateId',
|
||||||
|
type: 'options',
|
||||||
|
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
||||||
|
default: '',
|
||||||
|
typeOptions: {
|
||||||
|
loadOptionsMethod: 'getProjectTemplateId',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Custom Fields',
|
||||||
|
name: 'customFields',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
placeholder: 'Add Custom Field',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: true,
|
||||||
|
},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'project',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'create',
|
||||||
|
'update',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'Key value pairs containing the name and value of the custom field. Only dates in the format YYYY-MM-DD are accepted as input for custom date fields.',
|
||||||
|
default: [],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Custom Field',
|
||||||
|
name: 'customField',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Custom Field Name or ID',
|
||||||
|
name: '_id',
|
||||||
|
type: 'options',
|
||||||
|
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
||||||
|
default: '',
|
||||||
|
typeOptions: {
|
||||||
|
loadOptionsMethod: 'getProjectCustomField',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value Name or ID',
|
||||||
|
name: 'value',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'Custom Field\'s values',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Contributors',
|
||||||
|
name: 'contributorsUi',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
default: [],
|
||||||
|
placeholder: 'Add Person',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: true,
|
||||||
|
},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'project',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'update',
|
||||||
|
'create',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Contributors',
|
||||||
|
name: 'contributors',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Contributors: Name or ID',
|
||||||
|
name: 'value',
|
||||||
|
type: 'options',
|
||||||
|
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
||||||
|
default: '',
|
||||||
|
typeOptions: {
|
||||||
|
loadOptionsMethod: 'getUsers',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
description: 'Name or ID of the user to whom the task has been assigned. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/nodes/expressions.html#expressions">expression</a>.',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
displayName: 'Index',
|
displayName: 'Index',
|
||||||
name: 'index',
|
name: 'index',
|
||||||
|
@ -132,17 +256,7 @@ export const projectDescription: INodeProperties[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: 'Project Name or ID',
|
displayName: 'Project Name or ID',
|
||||||
name: 'name',
|
name: '_id',
|
||||||
type: 'options',
|
|
||||||
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
|
||||||
default: '',
|
|
||||||
typeOptions: {
|
|
||||||
loadOptionsMethod: 'getProjectId',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'Client Name or ID',
|
|
||||||
name: 'name',
|
|
||||||
type: 'options',
|
type: 'options',
|
||||||
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
||||||
default: '',
|
default: '',
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
|
@ -1,25 +1,25 @@
|
||||||
{
|
{
|
||||||
"name": "n8n-nodes-plutio",
|
"name": "n8n-nodes-plutio",
|
||||||
"version": "1.0.0",
|
"version": "0.1.0",
|
||||||
"description": "Custom Plutio node module for n8n.",
|
"description": "Custom n8n node module for Plutio.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"n8n-community-node-package"
|
"n8n-community-node-package"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://chykalophia.com",
|
"homepage": "https://chykalophia.com",
|
||||||
"contributors":
|
"contributors":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "Peter Krzyzek",
|
"name": "Peter Krzyzek",
|
||||||
"email": "peter@chykalophia.com",
|
"email": "peter@chykalophia.com",
|
||||||
"url": "https://chykalophia.com"
|
"url": "https://chykalophia.com"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Joel Sanguenza",
|
"name": "Joel Sanguenza",
|
||||||
"email": "joel@chykalophia.com",
|
"email": "joel@chykalophia.com",
|
||||||
"url": "https://chykalophia.com"
|
"url": "https://chykalophia.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.cklph.dev/Chykalophia/n8n-nodes-plutio.git"
|
"url": "https://git.cklph.dev/Chykalophia/n8n-nodes-plutio.git"
|
||||||
|
|
Loading…
Reference in New Issue