Initial commit to public repo

This commit is contained in:
Peter Krzyzek 2022-09-02 09:52:57 -05:00
parent 47b4fc9edc
commit 8dbfbb1b8d
17 changed files with 14953 additions and 1 deletions

View file

@ -0,0 +1,95 @@
import {
OptionsWithUri,
} from 'request';
import {
IExecuteFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import {
IDataObject, NodeApiError
} from 'n8n-workflow';
// Rest API for generating access token
async function plutioApiRequestToken(this: IExecuteFunctions | ILoadOptionsFunctions): Promise<any> { // tslint:disable-line:no-any
const credentials = await this.getCredentials('plutioApi');
const clientId = `${credentials.clientId}`;
const clientSecret = `${credentials.clientSecret}`;
const business = `${credentials.business}`;
const endpoint = 'api.plutio.com/v1.9';
const returnData: IDataObject[] = [];
let responseData;
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'business': business,
},
method: 'POST',
body: {
'client_id': clientId,
'client_secret': clientSecret,
'grant_type': 'client_credentials',
},
uri: `https://${endpoint}/oauth/token`,
json: true,
};
try {
responseData = await this.helpers.request!(options);
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else {
if (responseData === undefined) {
responseData = {
success: true,
};
}
returnData.push(responseData as IDataObject);
}
if (returnData[0].accessToken) {
return returnData[0].accessToken;
}
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
}
// 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
const endpoint = 'api.plutio.com/v1.9';
const credentials = await this.getCredentials('plutioApi');
const plutioApiToken = await plutioApiRequestToken.call(this);
const business = `${credentials.business}`;
let options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${Buffer.from(plutioApiToken).toString()}`,
'Business': business,
},
method,
body,
qs: query,
uri: uri || `https://${endpoint}${resource}`,
json: true,
};
if (!Object.keys(body).length) {
delete options.body;
}
if (!Object.keys(query).length) {
delete options.qs;
}
options = Object.assign({}, options, option);
try {
return await this.helpers.request!(options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
}
export function capitalize(s: string): string {
if (typeof s !== 'string') return '';
return s.charAt(0).toUpperCase() + s.slice(1);
}

871
nodes/Plutio/Plutio.node.ts Normal file
View file

@ -0,0 +1,871 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import {
IDataObject,
ILoadOptionsFunctions,
INodeExecutionData,
INodePropertyOptions,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import {
commentDescription,
commentOperations,
invoiceDescription,
invoiceOperations,
projectDescription,
projectOperations,
taskDescription,
taskOperations
} from './descriptions';
import {
plutioApiRequest,
} from './GenericFunctions';
interface IProperyId {}
interface ICreatePlutioBody {
assignedTo?: [string];
title?: string;
name?: string;
taskGroupId?: string;
createdBy?: string;
templateId?: string;
_id?: string;
descriptionHTML?: string;
entityId?: string;
entityType?: string;
bodyHTML?: string;
status?: string;
position?: number;
taskBoardId?: string;
projectId?: string;
customFields?: IDataObject[];
tax?: IDataObject[];
client?: IDataObject;
currency?: string;
discount?: string;
index?: number;
}
export class Plutio implements INodeType {
description: INodeTypeDescription = {
displayName: 'Plutio',
name: 'plutio',
icon: 'file:plutio.png',
group: ['output'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Plutio API',
defaults: {
name: 'Plutio',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'plutioApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
required: true,
options: [
{
name: 'Task',
value: 'task',
},
{
name: 'Comment',
value: 'comment',
},
{
name: 'Invoice',
value: 'invoice',
},
{
name: 'Project-CKLPH',
value: 'project',
},
],
default: 'task',
},
...taskOperations,
...taskDescription,
...commentOperations,
...commentDescription,
...invoiceOperations,
...invoiceDescription,
...projectOperations,
...projectDescription,
],
};
methods = {
loadOptions: {
// Get all the people to display them to user so that he can
// select them easily
async getUsers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const users = await plutioApiRequest.call(this, 'GET', '/people');
for (const user of users) {
const userName = (user.name.last) ? `${user.name.first} ${user.name.last}` : `${user.name.first}`;
const userId = user._id;
returnData.push({
name: userName,
value: userId,
});
}
return returnData;
},
// Get all the people to display them to user so that he can
// select them easily
async getEmails(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const users = await plutioApiRequest.call(this, 'GET', '/people');
for (const user of users) {
const userName = (user.name.last) ? `${user.name.first} ${user.name.last}` : `${user.name.first}`;
const email = (user.contactEmails[0].address) ? user.contactEmails[0].address : userName;
const userId = user._id;
returnData.push({
name: email,
value: userId,
});
}
return returnData;
},
async getTaskGroupId(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const ids = await plutioApiRequest.call(this, 'GET', '/task-groups');
for (const id of ids) {
const taskGroupName = id.title;
const taskGroupId = id._id;
returnData.push({
name: taskGroupName,
value: taskGroupId,
});
}
return returnData;
},
async getTaskBoardId(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const ids = await plutioApiRequest.call(this, 'GET', '/task-boards', {}, );
for (const id of ids) {
const taskBoardName = id.title;
const taskBoardId = id._id;
returnData.push({
name: taskBoardName,
value: taskBoardId,
});
}
return returnData;
},
async getTaskTemplateId(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const ids = await plutioApiRequest.call(this, 'GET', '/templates', {}, {'entityType': 'task'});
for (const id of ids) {
const templateName = id.title;
const templateId = id._id;
returnData.push({
name: templateName,
value: templateId,
});
}
return returnData;
},
async getInvoiceTemplateId(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const ids = await plutioApiRequest.call(this, 'GET', '/templates', {}, {'entityType': 'invoice'});
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[]> {
const returnData: INodePropertyOptions[] = [];
const ids = await plutioApiRequest.call(this, 'GET', '/projects');
for (const id of ids) {
const projectName = id.name;
const projectId = id._id;
returnData.push({
name: projectName,
value: projectId,
});
}
return returnData;
},
// Get all the custom fields to display them to user so that he can
// select them easily
async getCustomFieldTitle(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const fields = await plutioApiRequest.call(this, 'GET', '/custom-fields');
for (const field of fields) {
if ('task' === field.entityType) {
const fieldName = field.title;
const fieldValue = field._id;
returnData.push({
name: fieldName,
value: fieldValue,
});
}
}
return returnData;
},
},
};
// Execute REST Api functions
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
let responseData;
const items = this.getInputData();
const returnData: IDataObject[] = [];
const body: ICreatePlutioBody = {};
const qs: IDataObject = {};
const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string;
for (let i = 0; i < items.length; i++) {
try {
if ('task' === resource) {
if ('create' === operation) {
const assignees = this.getNodeParameter('assignees', i) as IDataObject;
const options = this.getNodeParameter('options', i) as IDataObject;
if (options.projectId) {
let projectId;
const ids = await plutioApiRequest.call(this, 'GET', '/projects');
for (const id of ids) {
if (options.projectId === id.name || options.projectId === id._id || options.projectId === id.nameSortKey) {
projectId = id._id;
}
}
body.projectId = projectId as string;
}
if (options.taskBoardId) {
let taskBoardId;
const qs = (body.projectId) ? {'projectId': body.projectId} : {};
const ids = await plutioApiRequest.call(this, 'GET', '/task-boards', {}, qs);
for (const id of ids) {
if (options.taskBoardId === id.title || options.taskBoardId === id._id) {
taskBoardId = id._id;
}
}
body.taskBoardId = taskBoardId as string;
}
if (options.taskGroupId) {
let taskGroupId;
const projectId = (body.projectId) ? body.projectId : {};
const taskBoardId = (body.taskBoardId) ? body.taskBoardId : {};
const qs = {projectId, taskBoardId};
const ids = await plutioApiRequest.call(this, 'GET', '/task-groups', {}, qs);
for (const id of ids) {
if (options.taskGroupId === id.title || options.taskGroupId === id._id) {
taskGroupId = id._id;
}
}
body.taskGroupId = taskGroupId as string;
}
if (options.createdBy) {
let creator;
const users = await plutioApiRequest.call(this, 'GET', '/people');
for (const user of users) {
const userName = (user.name.last) ? `${user.name.first} ${user.name.last}` : `${user.name.first}`;
const userId = user._id;
if (options.createdBy === userName || options.createdBy === userId) {
creator = userId;
}
}
body.createdBy = creator as string;
}
if (options.templateId) {
let templateId;
const ids = await plutioApiRequest.call(this, 'GET', '/templates');
for (const id of ids) {
if (options.templateId === id.title || options.templateId === id._id) {
templateId = id._id;
}
}
body.templateId = templateId as string;
}
if (options.title) {
body.title = options.title as string;
}
if (options.descriptionHTML) {
body.descriptionHTML = options.descriptionHTML as string;
}
if (options.customFields) {
const metadata = (options.customFields as IDataObject).customField as IDataObject[];
const customQs = {"$or":[{"inputType": "select"}, {"inputType": "multi"}],"entityType":"task"};
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;
delete options.customFields;
}
// add assign to user
if (assignees) {
const metadata = (assignees as IDataObject).assignee as IDataObject[];
let assignedTo: IProperyId[] = [];
const users: IProperyId[] = [];
if (metadata) {
// Push all assignees to a single array.
for (const data of metadata) {
assignedTo.push(data.value as IDataObject);
}
// flatten assignedTo array.
assignedTo = assignedTo.flatMap(a => a);
const customQs = {'status': 'active'};
await plutioApiRequest.call(this, 'GET', '/people', {}, customQs).then(people => {
for (const id of assignedTo) {
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.
assignedTo = users.filter((c, index) => {
return users.indexOf(c) === index;
});
body.assignedTo = assignedTo as [string];
}
responseData = await plutioApiRequest.call(this, 'POST', '/tasks', body);
}
if ('update' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
const assignees = this.getNodeParameter('assignees', i) as IDataObject;
const options = this.getNodeParameter('options', i) as IDataObject;
if (_id) {
body._id = _id as string;
}
if (options.projectId) {
let projectId;
const ids = await plutioApiRequest.call(this, 'GET', '/projects');
for (const id of ids) {
if (options.projectId === id.name || options.projectId === id._id || options.projectId === id.nameSortKey) {
projectId = id._id;
}
}
body.projectId = projectId as string;
}
if (options.taskBoardId) {
let taskBoardId;
const customQs = (body.projectId) ? {'projectId': body.projectId} : {};
const ids = await plutioApiRequest.call(this, 'GET', '/task-boards', {}, customQs);
for (const id of ids) {
if (options.taskBoardId === id.title || options.taskBoardId === id._id) {
taskBoardId = id._id;
}
}
body.taskBoardId = taskBoardId as string;
}
if (options.taskGroupId) {
const projectId = (body.projectId) ? body.projectId : {};
const taskBoardId = (body.taskBoardId) ? body.taskBoardId : {};
let taskGroupId;
const customQs = {projectId, taskBoardId};
const ids = await plutioApiRequest.call(this, 'GET', '/task-groups', {}, customQs);
for (const id of ids) {
if (options.taskGroupId === id.title || options.taskGroupId === id._id) {
taskGroupId = id._id;
}
}
body.taskGroupId = taskGroupId as string;
}
if (options.createdBy) {
let creator;
const users = await plutioApiRequest.call(this, 'GET', '/people');
for (const user of users) {
const userName = (user.name.last) ? `${user.name.first} ${user.name.last}` : `${user.name.first}`;
const userId = user._id;
if (options.createdBy === userName || options.createdBy === userId) {
creator = userId;
}
}
body.createdBy = creator as string;
}
if (options.templateId) {
let templateId;
const ids = await plutioApiRequest.call(this, 'GET', '/templates');
for (const id of ids) {
if (options.templateId === id.title || options.templateId === id._id) {
templateId = id._id;
}
}
body.templateId = templateId as string;
}
if (options.title) {
body.title = options.title as string;
}
if (options.descriptionHTML) {
body.descriptionHTML = options.descriptionHTML as string;
}
if (options.customFields) {
const metadata = (options.customFields as IDataObject).customField as IDataObject[];
const customQs = {"$or":[{"inputType": "select"}, {"inputType": "multi"}],"entityType":"task"};
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;
delete options.customFields;
}
if (assignees) {
const metadata = (assignees as IDataObject).assignee as IDataObject[];
let assignedTo: IProperyId[] = [];
const users: IProperyId[] = [];
// Push all assignees to a single array.
for (const data of metadata) {
assignedTo.push(data.value as IDataObject);
}
// flatten assignedTo array.
assignedTo = assignedTo.flatMap(a => a);
const customQs = {'status': 'active'};
await plutioApiRequest.call(this, 'GET', '/people', {}, customQs).then(people => {
for (const id of assignedTo) {
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.
assignedTo = users.filter((c, index) => {
return users.indexOf(c) === index;
});
body.assignedTo = assignedTo as [string];
}
responseData = await plutioApiRequest.call(this, 'PUT', '/tasks', body);
}
if ('get' === operation) {
const options = this.getNodeParameter('options', i) as IDataObject;
if (options._id) {
qs._id = options._id as string;
}
if (options.projectId) {
let projectId;
const ids = await plutioApiRequest.call(this, 'GET', '/projects');
for (const id of ids) {
if (options.projectId === id.name || options.projectId === id._id) {
projectId = id._id;
}
}
qs.projectId = projectId as string;
}
if (options.taskBoardId) {
let taskBoardId;
const ids = await plutioApiRequest.call(this, 'GET', '/task-boards');
for (const id of ids) {
if (options.taskBoardId === id.title || options.taskBoardId === id._id) {
taskBoardId = id._id;
}
}
qs.taskBoardId = taskBoardId as string;
}
if (options.taskGroupId) {
let taskGroupId;
const ids = await plutioApiRequest.call(this, 'GET', '/task-groups');
for (const id of ids) {
if (options.taskGroupId === id.title || options.taskGroupId === id._id) {
taskGroupId = id._id;
}
}
qs.taskGroupId = taskGroupId as string;
}
if (options.createdBy) {
let creator;
const users = await plutioApiRequest.call(this, 'GET', '/people');
for (const user of users) {
const userName = (user.name.last) ? `${user.name.first} ${user.name.last}` : `${user.name.first}`;
const userId = user._id;
if (options.createdBy === userName || options.createdBy === userId) {
creator = userId;
}
}
qs.createdBy = creator as string;
}
if (options.title) {
qs.title = options.title as string;
}
responseData = await plutioApiRequest.call(this, 'GET', '/tasks', {}, qs);
}
if ('copy' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
const taskGroupId = this.getNodeParameter('taskGroupId', 0) as string;
const position = this.getNodeParameter('position', i) as number;
if (_id) {
body._id = _id as string;
}
if (taskGroupId) {
let taskGroup;
const ids = await plutioApiRequest.call(this, 'GET', '/task-groups');
for (const id of ids) {
if (taskGroupId === id.title || taskGroupId === id._id) {
taskGroup = id._id;
}
}
body.taskGroupId = taskGroup as string;
}
if (position as number) {
body.position = position as number;
}
responseData = await plutioApiRequest.call(this, 'POST', '/tasks/copy', body);
}
if ('move' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
const taskGroupId = this.getNodeParameter('taskGroupId', 0) as string;
const position = this.getNodeParameter('position', i) as number;
if (_id) {
body._id = _id as string;
}
if (taskGroupId) {
let taskGroup;
const ids = await plutioApiRequest.call(this, 'GET', '/task-groups');
for (const id of ids) {
if (taskGroupId === id.title || taskGroupId === id._id) {
taskGroup = id._id;
}
}
body.taskGroupId = taskGroup as string;
}
if (position as number) {
body.position = position as number;
}
responseData = await plutioApiRequest.call(this, 'POST', '/tasks/move', body);
}
if ('delete' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
if (_id) {
body._id = _id as string;
}
responseData = await plutioApiRequest.call(this, 'DELETE', '/tasks', body);
}
}
if ('comment' === resource) {
if ('create' === operation) {
const entityId = this.getNodeParameter('entityId', i) as string;
const entityType = this.getNodeParameter('entityType', i) as string;
const bodyHTML = this.getNodeParameter('bodyHTML', i) as string;
if (entityId) {
body.entityId = entityId as string;
}
if (entityType) {
body.entityType = entityType as string;
}
if (bodyHTML) {
body.bodyHTML = bodyHTML as string;
}
responseData = await plutioApiRequest.call(this, 'POST', '/comments', body);
}
if ('get' === operation) {
const entityId = this.getNodeParameter('entityId', i) as string;
const entityType = this.getNodeParameter('entityType', i) as string;
if (entityId) {
qs.entityId = entityId as string;
}
if (entityType) {
qs.entityType = entityType as string;
}
responseData = await plutioApiRequest.call(this, 'GET', '/comments', {}, qs);
}
if ('update' === operation) {
const _id = this.getNodeParameter('_id', i) as string;
const bodyHTML = this.getNodeParameter('bodyHTML', i) as string;
if (_id) {
body._id = _id as string;
}
if (bodyHTML) {
body.bodyHTML = bodyHTML as string;
}
responseData = await plutioApiRequest.call(this, 'PUT', '/comments', body);
}
if ('delete' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
if (_id) {
body._id = _id as string;
}
responseData = await plutioApiRequest.call(this, 'DELETE', '/comments', body);
}
}
if ('invoice' === resource) {
if ('create' === operation) {
const taxUi = this.getNodeParameter('taxUi', i) as IDataObject;
const clientUi = this.getNodeParameter('clientUi', i) as IDataObject;
const options = this.getNodeParameter('options', i) as IDataObject;
if (taxUi) {
const metadata = (taxUi as IDataObject).tax as IDataObject[];
body.tax = metadata;
}
if (clientUi) {
const client = (clientUi as IDataObject).client as IDataObject;
if ('person' === client.entityType) {
await plutioApiRequest.call(this, 'GET', '/people').then(people => {
for (const person of people) {
const userName = (person.name.last) ? `${person.name.first} ${person.name.last}` : `${person.name.first}`;
if (client._id === person._id || userName === client._id) {
client._id = person._id;
}
}
});
} else {
await plutioApiRequest.call(this, 'GET', '/companies').then(companies => {
for (const company of companies) {
if (company.title === client._id || company._id === client._id || company.titleSortKey === client._id) {
client._id = company._id;
}
}
});
}
body.client = client as IDataObject;
}
if (options.name) {
body.name = options.name as string;
}
if (options.currency) {
body.currency = options.currency as string;
}
if (options.discount) {
body.discount = `${options.discount}%` as string;
}
if (options.templateId) {
await plutioApiRequest.call(this, 'GET', '/templates', {}, {'entityType': 'invoice'}).then(templates => {
for (const template of templates) {
options.templateId = template._id;
}
});
body.templateId = options.templateId as string;
}
responseData = await plutioApiRequest.call(this, 'POST', '/invoices', body);
}
if ('get' === operation) {
const options = this.getNodeParameter('options', i) as IDataObject;
if (options._id) {
qs._id = options._id as string;
}
if (options.name) {
qs.name = options.name as string;
}
if (options.currency) {
qs.currency = options.currency as string;
}
if (options.status) {
qs.status = options.status as string;
}
if (options.discount) {
qs.discount = `${options.discount}%` as string;
}
responseData = await plutioApiRequest.call(this, 'GET', '/invoices', {}, qs);
}
if ('update' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
const options = this.getNodeParameter('options', i) as IDataObject;
const taxUi = this.getNodeParameter('taxUi', i) as IDataObject;
const clientUi = this.getNodeParameter('clientUi', i) as IDataObject;
if (_id) {
body._id = _id as string;
}
if (taxUi) {
const metadata = (taxUi as IDataObject).tax as IDataObject[];
body.tax = metadata;
}
if (clientUi) {
const client = (clientUi as IDataObject).client as IDataObject;
if ('person' === client.entityType) {
await plutioApiRequest.call(this, 'GET', '/people').then(people => {
for (const person of people) {
const userName = (person.name.last) ? `${person.name.first} ${person.name.last}` : `${person.name.first}`;
if (client._id === person._id || userName === client._id) {
client._id = person._id;
}
}
});
} else {
await plutioApiRequest.call(this, 'GET', '/companies').then(companies => {
for (const company of companies) {
if (company.title === client._id || company._id === client._id || company.titleSortKey === client._id) {
client._id = company._id;
}
}
});
}
body.client = client as IDataObject;
}
if (options.name) {
body.name = options.name as string;
}
if (options.currency) {
body.currency = options.currency as string;
}
if (options.status) {
body.status = options.status as string;
}
if (options.discount) {
body.status = `${options.discount}%` as string;
}
responseData = await plutioApiRequest.call(this, 'PUT', '/invoices', body);
}
if ('delete' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
if (_id) {
body._id = _id as string;
}
responseData = await plutioApiRequest.call(this, 'DELETE', '/invoices', body);
}
}
if ('project' === resource) {
if ('getCklph' === operation) {
const contributor = this.getNodeParameter('contributor', i) as IDataObject;
if (contributor) {
let contributorId;
const users = await plutioApiRequest.call(this, 'GET', '/people');
for (const user of users) {
if (user.contactEmails[0].address === contributor || contributor === user._id) {
contributorId = user._id;
}
}
qs.contributors = contributorId as string;
}
const project = await plutioApiRequest.call(this, 'GET', '/projects', {}, qs);
if (project.length === 1) {
responseData = project;
} else {
responseData = {'name': 'default'};
}
}
if ('move' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
const index = this.getNodeParameter('index', 0) as number;
if (_id) {
body._id = _id as string;
}
if (index) {
body.index = index as number;
}
responseData = await plutioApiRequest.call(this, 'POST', '/projects/move', body);
}
if ('copy' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
const index = this.getNodeParameter('index', 0) as number;
if (_id) {
body._id = _id as string;
}
if (index) {
body.index = index as number;
}
responseData = await plutioApiRequest.call(this, 'POST', '/projects/copy', body);
}
if ('delete' === operation) {
const _id = this.getNodeParameter('_id', 0) as string;
if (_id) {
body._id = _id as string;
}
responseData = await plutioApiRequest.call(this, 'DELETE', '/projects', body);
}
}
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else {
if (responseData === undefined) {
responseData = {
success: true,
};
}
returnData.push(responseData as IDataObject);
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message });
continue;
}
throw error;
}
}
return [this.helpers.returnJsonArray(returnData)];
}
}

View file

@ -0,0 +1,137 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const commentOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
required: true,
displayOptions: {
show: {
resource: [
'comment',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new comment',
action: 'Create a comment',
},
{
name: 'Get',
value: 'get',
description: 'Get Comments',
action: 'Get a comment',
},
{
name: 'Update',
value: 'update',
description: 'Update a comment',
action: 'Update a comment',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a comment',
action: 'Delete a comment',
},
],
default: 'create',
},
];
export const commentDescription: INodeProperties[] = [
{
displayName: 'Entity ID',
name: 'entityId',
type: 'string',
default: '',
displayOptions: {
show: {
resource: [
'comment',
],
operation: [
'create',
'get',
],
},
},
description: 'Entity ID of comment(could be task ID, conversation ID or file ID)',
},
{
displayName: 'Entity Type',
name: 'entityType',
type: 'options',
displayOptions: {
show: {
resource: [
'comment',
],
operation: [
'create',
'get',
],
},
},
options: [
{
name: 'File',
value: 'file',
},
{
name: 'Conversation',
value: 'conversation',
},
{
name: 'Task',
value: 'task',
},
],
default: 'task',
},
{
displayName: 'Comment ID',
name: '_id',
required: true,
type: 'string',
default: '',
displayOptions: {
show: {
resource: [
'comment',
],
operation: [
'update',
'delete',
],
},
},
description: 'For GET operation Comment ID or entityType & entityID is required',
},
{
displayName: 'Body',
name: 'bodyHTML',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: [
'comment',
],
operation: [
'update',
'create',
],
},
},
description: 'Comment Body',
},
];

View file

@ -0,0 +1,377 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const invoiceOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
required: true,
displayOptions: {
show: {
resource: [
'invoice',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new invoice',
action: 'Create an invoice',
},
{
name: 'Get',
value: 'get',
description: 'Get invoices',
action: 'Get an invoice',
},
{
name: 'Update',
value: 'update',
description: 'Update an invoice',
action: 'Update an invoice',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete an invoice',
action: 'Delete an invoice',
},
],
default: 'create',
},
];
export const invoiceDescription: INodeProperties[] = [
{
displayName: 'Invoice ID',
name: '_id',
type: 'string',
default: '',
displayOptions: {
show: {
resource: [
'invoice',
],
operation: [
'update',
'delete',
],
},
},
description: 'Should be a number or string for discount percentage',
},
{
displayName: 'Tax',
name: 'taxUi',
type: 'fixedCollection',
placeholder: 'Add Tax',
description: 'Key value pairs containing the title and value of the tax',
displayOptions: {
show: {
resource: [
'invoice',
],
operation: [
'create',
'update',
],
},
},
typeOptions: {
multipleValues: true,
},
default: [],
options: [
{
displayName: 'Tax',
name: 'tax',
values: [
{
displayName: 'Title',
name: 'title',
type: 'string',
default: '',
description: 'Tax title',
},
{
displayName: 'Value',
name: 'value',
type: 'number',
default: '',
description: 'Tax value',
},
],
},
],
},
{
displayName: 'Client',
name: 'clientUi',
type: 'fixedCollection',
placeholder: 'Add Client',
description: 'Key value pairs containing the title and value of the tax',
default: [],
displayOptions: {
show: {
resource: [
'invoice',
],
operation: [
'create',
'update',
],
},
},
options: [
{
displayName: 'Client',
name: 'client',
values: [
{
displayName: 'Entity Type',
name: 'entityType',
type: 'options',
default: 'person',
options: [
{
name: 'Person',
value: 'person',
},
{
name: 'Company',
value: 'company',
},
],
description: 'Entity Type could be a person or company',
},
{
displayName: 'Entity Name or ID',
name: '_id',
type: 'string',
default: '',
description: 'Could be a person or company\'s name or ID',
},
],
},
],
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: [
'invoice',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Invoice Name',
name: 'name',
type: 'string',
default: '',
description: 'Min-Max Character: 1-500',
},
{
displayName: 'Currency',
name: 'currency',
type: 'options',
default: 'USD',
options: [
{
name: 'USD',
value: 'USD',
},
{
name: 'EUR',
value: 'EUR',
},
],
},
{
displayName: 'Discount',
name: 'discount',
type: 'number',
default: '',
description: 'Should be a number for discount percentage',
},
{
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: 'getInvoiceTemplateId',
},
},
],
},
// Options for GET Request
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: [
'invoice',
],
operation: [
'get',
],
},
},
options: [
{
displayName: 'Invoice ID',
name: '_id',
type: 'string',
default: '',
description: 'Should be a number for discount percentage',
},
{
displayName: 'Invoice Name',
name: 'name',
type: 'string',
default: '',
description: 'Min-Max Character: 1-500',
},
{
displayName: 'Currency',
name: 'currency',
type: 'options',
default: 'USD',
options: [
{
name: 'USD',
value: 'USD',
},
{
name: 'EUR',
value: 'EUR',
},
],
},
{
displayName: 'Status',
name: 'status',
type: 'options',
default: 'draft',
options: [
{
name: 'Draft',
value: 'draft',
},
{
name: 'Pending',
value: 'pending',
},
{
name: 'Paid',
value: 'paid',
},
{
name: 'Cancelled',
value: 'cancelled',
},
],
},
{
displayName: 'Discount',
name: 'discount',
type: 'number',
default: '',
description: 'Should be a number for discount percentage',
},
],
},
// Options for Update Operation
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: [
'invoice',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Invoice Name',
name: 'name',
type: 'string',
default: '',
description: 'Min-Max Character: 1-500',
},
{
displayName: 'Currency',
name: 'currency',
type: 'options',
default: 'USD',
options: [
{
name: 'USD',
value: 'USD',
},
{
name: 'EUR',
value: 'EUR',
},
],
},
{
displayName: 'Status',
name: 'status',
type: 'options',
default: 'draft',
options: [
{
name: 'Draft',
value: 'draft',
},
{
name: 'Pending',
value: 'pending',
},
{
name: 'Paid',
value: 'paid',
},
{
name: 'Cancelled',
value: 'cancelled',
},
],
},
{
displayName: 'Discount',
name: 'discount',
type: 'number',
default: '',
description: 'Should be a number for discount percentage',
},
],
},
];

View file

@ -0,0 +1,175 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const projectOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
required: true,
displayOptions: {
show: {
resource: [
'project',
],
},
},
options: [
{
name: 'Copy',
value: 'copy',
description: 'Copy a project',
action: 'Copy a project',
},
{
name: 'Create',
value: 'create',
description: 'Create a new project',
action: 'Create a project',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a project',
action: 'Delete a project',
},
{
name: 'Get',
value: 'get',
description: 'Get projects',
action: 'Get a project',
},
{
name: 'Get CKLPH',
value: 'getCklph',
description: 'Get projects by contributor\'s email for CKLPH',
action: 'Get a project',
},
{
name: 'Move',
value: 'move',
description: 'Move a project',
action: 'Move a project',
},
{
name: 'Update',
value: 'update',
description: 'Update a project',
action: 'Update a project',
},
],
default: 'getCklph',
},
];
export const projectDescription: INodeProperties[] = [
{
displayName: 'Project ID',
name: '_id',
type: 'string',
default: '',
displayOptions: {
show: {
resource: [
'project',
],
operation: [
'update',
'move',
'copy',
'delete',
],
},
},
description: 'ID of Project',
},
{
displayName: 'Index',
name: 'index',
type: 'number',
default: '',
displayOptions: {
show: {
resource: [
'project',
],
operation: [
'move',
'copy',
],
},
},
description: 'Should be a number representing project ID after which project should be moved',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: [
'project',
],
operation: [
'get',
],
},
},
options: [
{
displayName: 'Contributor\'s Email\, Name or ID',
name: 'contributor',
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: 'getEmails',
},
},
{
displayName: 'Project Name or ID',
name: 'name',
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',
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: 'Contributor\'s Email\, Name or ID',
name: 'contributor',
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: 'getEmails',
},
displayOptions: {
show: {
resource: [
'project',
],
operation: [
'getCklph',
],
},
},
},
];

View file

@ -0,0 +1,358 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const taskOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
required: true,
displayOptions: {
show: {
resource: [
'task',
],
},
},
options: [
{
name: 'Copy',
value: 'copy',
description: 'Copy a task',
action: 'Copy a task',
},
{
name: 'Create',
value: 'create',
description: 'Create a new task',
action: 'Create a task',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a task',
action: 'Delete a task',
},
{
name: 'Get',
value: 'get',
description: 'Get tasks',
action: 'Get a task',
},
{
name: 'Move',
value: 'move',
description: 'Move a task',
action: 'Move a task',
},
{
name: 'Update',
value: 'update',
description: 'Update a task',
action: 'Update a task',
},
],
default: 'create',
},
];
export const taskDescription: INodeProperties[] = [
{
displayName: 'Task ID',
name: '_id',
type: 'string',
default: '',
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'update',
'move',
'copy',
'delete',
],
},
},
description: 'ID of task',
},
// Options for creating and updating task.
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'create',
'update',
],
},
},
options: [
{
displayName: 'Project Name or ID',
name: 'projectId',
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: 'Task Board Name or ID',
name: 'taskBoardId',
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: 'getTaskBoardId',
},
},
{
displayName: 'Task Group Name or ID',
name: 'taskGroupId',
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: 'getTaskGroupId',
},
},
{
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: 'getTaskTemplateId',
},
},
{
displayName: 'Creator Name or ID',
name: 'createdBy',
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',
},
},
{
displayName: 'Title',
name: 'title',
type: 'string',
default: '',
description: 'Title of the task',
},
{
displayName: 'Description',
name: 'descriptionHTML',
type: 'string',
default: '',
description: 'Request Description',
},
{
displayName: 'Custom Fields',
name: 'customFields',
type: 'fixedCollection',
placeholder: 'Add Custom Field',
typeOptions: {
multipleValues: true,
},
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: 'getCustomFieldTitle',
},
},
{
displayName: 'Value Name or ID',
name: 'value',
type: 'string',
default: '',
description: 'Custom Field\'s values',
},
],
},
],
},
],
},
{
displayName: 'Assigned To: Name or ID',
name: 'assignees',
type: 'fixedCollection',
default: [],
placeholder: 'Add Person',
typeOptions: {
multipleValues: true,
},
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'update',
'create',
],
},
},
options: [
{
displayName: 'Assignee',
name: 'assignee',
values: [
{
displayName: 'Assigned To: 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>.',
},
// move & copy task operation
{
displayName: 'Task Group Name or ID',
name: 'taskGroupId',
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: 'getTaskGroupId',
},
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'move',
'copy',
],
},
},
},
{
displayName: 'Position',
name: 'position',
type: 'number',
default: '',
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'move',
'copy',
],
},
},
description: 'Should be a number representing task ID after which task should be moved',
},
// Options for GET request
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'get',
],
},
},
options: [
{
displayName: 'Task ID',
name: '_id',
type: 'string',
default: '',
description: 'ID of task',
},
{
displayName: 'Project Name or ID',
name: 'projectId',
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: 'Task Board Name or ID',
name: 'taskBoardId',
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: 'getTaskBoardId',
},
},
{
displayName: 'Task Group Name or ID',
name: 'taskGroupId',
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: 'getTaskGroupId',
},
},
{
displayName: 'Creator Name or ID',
name: 'createdBy',
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',
},
},
{
displayName: 'Title',
name: 'title',
type: 'string',
default: '',
},
],
},
];

View file

@ -0,0 +1,15 @@
import { taskDescription, taskOperations } from './TaskDescription';
import { commentDescription, commentOperations } from './CommentDescription';
import { invoiceDescription, invoiceOperations } from './InvoiceDescription';
import { projectDescription, projectOperations } from './ProjectDescription';
export {
taskOperations,
taskDescription,
commentOperations,
commentDescription,
invoiceOperations,
invoiceDescription,
projectOperations,
projectDescription,
};

BIN
nodes/Plutio/plutio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB