mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
⚡ Renamed to Keap.
This commit is contained in:
parent
e8a8d31a97
commit
3a71e2c978
|
@ -7,12 +7,12 @@ const scopes = [
|
||||||
'full',
|
'full',
|
||||||
];
|
];
|
||||||
|
|
||||||
export class InfusionsoftOAuth2Api implements ICredentialType {
|
export class KeapOAuth2Api implements ICredentialType {
|
||||||
name = 'infusionsoftOAuth2Api';
|
name = 'keapOAuth2Api';
|
||||||
extends = [
|
extends = [
|
||||||
'oAuth2Api',
|
'oAuth2Api',
|
||||||
];
|
];
|
||||||
displayName = 'Infusionsoft OAuth2 API';
|
displayName = 'Keap OAuth2 API';
|
||||||
properties = [
|
properties = [
|
||||||
{
|
{
|
||||||
displayName: 'Authorization URL',
|
displayName: 'Authorization URL',
|
|
@ -17,7 +17,7 @@ export const contactOperations = [
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: 'Create/Update',
|
name: 'Create/Update',
|
||||||
value: 'create/update',
|
value: 'upsert',
|
||||||
description: 'Create/update a contact',
|
description: 'Create/update a contact',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,7 @@ export const contactOperations = [
|
||||||
description: 'Retrieve all contacts',
|
description: 'Retrieve all contacts',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
default: 'create/update',
|
default: 'upsert',
|
||||||
description: 'The operation to perform.',
|
description: 'The operation to perform.',
|
||||||
},
|
},
|
||||||
] as INodeProperties[];
|
] as INodeProperties[];
|
||||||
|
@ -44,7 +44,7 @@ export const contactOperations = [
|
||||||
export const contactFields = [
|
export const contactFields = [
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* contact:create/update */
|
/* contact:upsert */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
{
|
{
|
||||||
displayName: 'Duplicate Option',
|
displayName: 'Duplicate Option',
|
||||||
|
@ -64,7 +64,7 @@ export const contactFields = [
|
||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: [
|
operation: [
|
||||||
'create/update',
|
'upsert',
|
||||||
],
|
],
|
||||||
resource: [
|
resource: [
|
||||||
'contact',
|
'contact',
|
||||||
|
@ -84,7 +84,7 @@ export const contactFields = [
|
||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: [
|
operation: [
|
||||||
'create/update',
|
'upsert',
|
||||||
],
|
],
|
||||||
resource: [
|
resource: [
|
||||||
'contact',
|
'contact',
|
||||||
|
@ -250,7 +250,7 @@ export const contactFields = [
|
||||||
'contact',
|
'contact',
|
||||||
],
|
],
|
||||||
operation: [
|
operation: [
|
||||||
'create/update',
|
'upsert',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -349,7 +349,7 @@ export const contactFields = [
|
||||||
'contact',
|
'contact',
|
||||||
],
|
],
|
||||||
operation: [
|
operation: [
|
||||||
'create/update',
|
'upsert',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -403,7 +403,7 @@ export const contactFields = [
|
||||||
'contact',
|
'contact',
|
||||||
],
|
],
|
||||||
operation: [
|
operation: [
|
||||||
'create/update',
|
'upsert',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -453,7 +453,7 @@ export const contactFields = [
|
||||||
'contact',
|
'contact',
|
||||||
],
|
],
|
||||||
operation: [
|
operation: [
|
||||||
'create/update',
|
'upsert',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -515,7 +515,7 @@ export const contactFields = [
|
||||||
'contact',
|
'contact',
|
||||||
],
|
],
|
||||||
operation: [
|
operation: [
|
||||||
'create/update',
|
'upsert',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
|
@ -17,7 +17,7 @@ import {
|
||||||
snakeCase,
|
snakeCase,
|
||||||
} from 'change-case';
|
} from 'change-case';
|
||||||
|
|
||||||
export async function infusionsoftApiRequest(this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
export async function keapApiRequest(this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||||
let options: OptionsWithUri = {
|
let options: OptionsWithUri = {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
@ -37,7 +37,7 @@ export async function infusionsoftApiRequest(this: IWebhookFunctions | IHookFunc
|
||||||
delete options.body;
|
delete options.body;
|
||||||
}
|
}
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
return await this.helpers.requestOAuth.call(this, 'infusionsoftOAuth2Api', options);
|
return await this.helpers.requestOAuth.call(this, 'keapOAuth2Api', options);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.body && error.response.body.message) {
|
if (error.response && error.response.body && error.response.body.message) {
|
||||||
// Try to return the error prettier
|
// Try to return the error prettier
|
||||||
|
@ -47,7 +47,7 @@ export async function infusionsoftApiRequest(this: IWebhookFunctions | IHookFunc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function infusionsoftApiRequestAllItems(this: IHookFunctions| IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
export async function keapApiRequestAllItems(this: IHookFunctions| IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||||
|
|
||||||
const returnData: IDataObject[] = [];
|
const returnData: IDataObject[] = [];
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ export async function infusionsoftApiRequestAllItems(this: IHookFunctions| IExec
|
||||||
query.limit = 50;
|
query.limit = 50;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
responseData = await infusionsoftApiRequest.call(this, method, endpoint, body, query, uri);
|
responseData = await keapApiRequest.call(this, method, endpoint, body, query, uri);
|
||||||
uri = responseData.next;
|
uri = responseData.next;
|
||||||
returnData.push.apply(returnData, responseData[propertyName]);
|
returnData.push.apply(returnData, responseData[propertyName]);
|
||||||
} while (
|
} while (
|
|
@ -13,8 +13,8 @@ import {
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
infusionsoftApiRequest,
|
keapApiRequest,
|
||||||
infusionsoftApiRequestAllItems,
|
keapApiRequestAllItems,
|
||||||
keysToSnakeCase,
|
keysToSnakeCase,
|
||||||
} from './GenericFunctions';
|
} from './GenericFunctions';
|
||||||
|
|
||||||
|
@ -101,24 +101,24 @@ import {
|
||||||
|
|
||||||
import * as moment from 'moment-timezone';
|
import * as moment from 'moment-timezone';
|
||||||
|
|
||||||
export class Infusionsoft implements INodeType {
|
export class Keap implements INodeType {
|
||||||
description: INodeTypeDescription = {
|
description: INodeTypeDescription = {
|
||||||
displayName: 'Infusionsoft',
|
displayName: 'Keap',
|
||||||
name: ' infusionsoft',
|
name: ' keap',
|
||||||
icon: 'file:infusionsoft.png',
|
icon: 'file:keap.png',
|
||||||
group: ['input'],
|
group: ['input'],
|
||||||
version: 1,
|
version: 1,
|
||||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||||
description: 'Consume Infusionsoft API.',
|
description: 'Consume Keap API.',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: 'Infusionsoft',
|
name: 'Keap',
|
||||||
color: '#79af53',
|
color: '#79af53',
|
||||||
},
|
},
|
||||||
inputs: ['main'],
|
inputs: ['main'],
|
||||||
outputs: ['main'],
|
outputs: ['main'],
|
||||||
credentials: [
|
credentials: [
|
||||||
{
|
{
|
||||||
name: 'infusionsoftOAuth2Api',
|
name: 'keapOAuth2Api',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -197,7 +197,7 @@ export class Infusionsoft implements INodeType {
|
||||||
// select them easily
|
// select them easily
|
||||||
async getTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
async getTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
const returnData: INodePropertyOptions[] = [];
|
const returnData: INodePropertyOptions[] = [];
|
||||||
const tags = await infusionsoftApiRequestAllItems.call(this, 'tags', 'GET', '/tags');
|
const tags = await keapApiRequestAllItems.call(this, 'tags', 'GET', '/tags');
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
const tagName = tag.name;
|
const tagName = tag.name;
|
||||||
const tagId = tag.id;
|
const tagId = tag.id;
|
||||||
|
@ -212,7 +212,7 @@ export class Infusionsoft implements INodeType {
|
||||||
// select them easily
|
// select them easily
|
||||||
async getUsers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
async getUsers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
const returnData: INodePropertyOptions[] = [];
|
const returnData: INodePropertyOptions[] = [];
|
||||||
const users = await infusionsoftApiRequestAllItems.call(this, 'users', 'GET', '/users');
|
const users = await keapApiRequestAllItems.call(this, 'users', 'GET', '/users');
|
||||||
for (const user of users) {
|
for (const user of users) {
|
||||||
const userName = user.given_name;
|
const userName = user.given_name;
|
||||||
const userId = user.id;
|
const userId = user.id;
|
||||||
|
@ -227,7 +227,7 @@ export class Infusionsoft implements INodeType {
|
||||||
// select them easily
|
// select them easily
|
||||||
async getCountries(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
async getCountries(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
const returnData: INodePropertyOptions[] = [];
|
const returnData: INodePropertyOptions[] = [];
|
||||||
const { countries } = await infusionsoftApiRequest.call(this, 'GET', '/locales/countries');
|
const { countries } = await keapApiRequest.call(this, 'GET', '/locales/countries');
|
||||||
for (const key of Object.keys(countries)) {
|
for (const key of Object.keys(countries)) {
|
||||||
const countryName = countries[key];
|
const countryName = countries[key];
|
||||||
const countryId = key;
|
const countryId = key;
|
||||||
|
@ -243,7 +243,7 @@ export class Infusionsoft implements INodeType {
|
||||||
async getProvinces(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
async getProvinces(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
const countryCode = this.getCurrentNodeParameter('countryCode') as string;
|
const countryCode = this.getCurrentNodeParameter('countryCode') as string;
|
||||||
const returnData: INodePropertyOptions[] = [];
|
const returnData: INodePropertyOptions[] = [];
|
||||||
const { provinces } = await infusionsoftApiRequest.call(this, 'GET', `/locales/countries/${countryCode}/provinces`);
|
const { provinces } = await keapApiRequest.call(this, 'GET', `/locales/countries/${countryCode}/provinces`);
|
||||||
for (const key of Object.keys(provinces)) {
|
for (const key of Object.keys(provinces)) {
|
||||||
const provinceName = provinces[key];
|
const provinceName = provinces[key];
|
||||||
const provinceId = key;
|
const provinceId = key;
|
||||||
|
@ -258,7 +258,7 @@ export class Infusionsoft implements INodeType {
|
||||||
// select them easily
|
// select them easily
|
||||||
async getContactTypes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
async getContactTypes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
const returnData: INodePropertyOptions[] = [];
|
const returnData: INodePropertyOptions[] = [];
|
||||||
const types = await infusionsoftApiRequest.call(this, 'GET', '/setting/contact/optionTypes');
|
const types = await keapApiRequest.call(this, 'GET', '/setting/contact/optionTypes');
|
||||||
for (const type of types.value.split(',')) {
|
for (const type of types.value.split(',')) {
|
||||||
const typeName = type;
|
const typeName = type;
|
||||||
const typeId = type;
|
const typeId = type;
|
||||||
|
@ -296,7 +296,7 @@ export class Infusionsoft implements INodeType {
|
||||||
const operation = this.getNodeParameter('operation', 0) as string;
|
const operation = this.getNodeParameter('operation', 0) as string;
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
if (resource === 'company') {
|
if (resource === 'company') {
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Company/createCompanyUsingPOST
|
//https://developer.keap.com/docs/rest/#!/Company/createCompanyUsingPOST
|
||||||
if (operation === 'create') {
|
if (operation === 'create') {
|
||||||
const addresses = (this.getNodeParameter('addressesUi', i) as IDataObject).addressesValues as IDataObject[];
|
const addresses = (this.getNodeParameter('addressesUi', i) as IDataObject).addressesValues as IDataObject[];
|
||||||
const faxes = (this.getNodeParameter('faxesUi', i) as IDataObject).faxesValues as IDataObject[];
|
const faxes = (this.getNodeParameter('faxesUi', i) as IDataObject).faxesValues as IDataObject[];
|
||||||
|
@ -317,7 +317,7 @@ export class Infusionsoft implements INodeType {
|
||||||
if (phones) {
|
if (phones) {
|
||||||
body.phone_number = phones[0];
|
body.phone_number = phones[0];
|
||||||
}
|
}
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'POST', '/companies', body);
|
responseData = await keapApiRequest.call(this, 'POST', '/companies', body);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Company/listCompaniesUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/Company/listCompaniesUsingGET
|
||||||
if (operation === 'getAll') {
|
if (operation === 'getAll') {
|
||||||
|
@ -330,17 +330,17 @@ export class Infusionsoft implements INodeType {
|
||||||
delete qs.fields;
|
delete qs.fields;
|
||||||
}
|
}
|
||||||
if (returnAll) {
|
if (returnAll) {
|
||||||
responseData = await infusionsoftApiRequestAllItems.call(this, 'companies', 'GET', '/companies', {}, qs);
|
responseData = await keapApiRequestAllItems.call(this, 'companies', 'GET', '/companies', {}, qs);
|
||||||
} else {
|
} else {
|
||||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', '/companies', {}, qs);
|
responseData = await keapApiRequest.call(this, 'GET', '/companies', {}, qs);
|
||||||
responseData = responseData.companies;
|
responseData = responseData.companies;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (resource === 'contact') {
|
if (resource === 'contact') {
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Contact/createOrUpdateContactUsingPUT
|
//https://developer.infusionsoft.com/docs/rest/#!/Contact/createOrUpdateContactUsingPUT
|
||||||
if (operation === 'create/update') {
|
if (operation === 'upsert') {
|
||||||
const duplicateOption = this.getNodeParameter('duplicateOption', i) as string;
|
const duplicateOption = this.getNodeParameter('duplicateOption', i) as string;
|
||||||
const addresses = (this.getNodeParameter('addressesUi', i) as IDataObject).addressesValues as IDataObject[];
|
const addresses = (this.getNodeParameter('addressesUi', i) as IDataObject).addressesValues as IDataObject[];
|
||||||
const emails = (this.getNodeParameter('emailsUi', i) as IDataObject).emailsValues as IDataObject[];
|
const emails = (this.getNodeParameter('emailsUi', i) as IDataObject).emailsValues as IDataObject[];
|
||||||
|
@ -421,12 +421,12 @@ export class Infusionsoft implements INodeType {
|
||||||
if (phones) {
|
if (phones) {
|
||||||
body.phone_numbers = phones as IPhone[];
|
body.phone_numbers = phones as IPhone[];
|
||||||
}
|
}
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'PUT', '/contacts', body);
|
responseData = await keapApiRequest.call(this, 'PUT', '/contacts', body);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Contact/deleteContactUsingDELETE
|
//https://developer.infusionsoft.com/docs/rest/#!/Contact/deleteContactUsingDELETE
|
||||||
if (operation === 'delete') {
|
if (operation === 'delete') {
|
||||||
const contactId = parseInt(this.getNodeParameter('contactId', i) as string, 10);
|
const contactId = parseInt(this.getNodeParameter('contactId', i) as string, 10);
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'DELETE', `/contacts/${contactId}`);
|
responseData = await keapApiRequest.call(this, 'DELETE', `/contacts/${contactId}`);
|
||||||
responseData = { success: true };
|
responseData = { success: true };
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Contact/getContactUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/Contact/getContactUsingGET
|
||||||
|
@ -436,7 +436,7 @@ export class Infusionsoft implements INodeType {
|
||||||
if (options.fields) {
|
if (options.fields) {
|
||||||
qs.optional_properties = options.fields as string;
|
qs.optional_properties = options.fields as string;
|
||||||
}
|
}
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', `/contacts/${contactId}`, {}, qs);
|
responseData = await keapApiRequest.call(this, 'GET', `/contacts/${contactId}`, {}, qs);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Contact/listContactsUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/Contact/listContactsUsingGET
|
||||||
if (operation === 'getAll') {
|
if (operation === 'getAll') {
|
||||||
|
@ -464,10 +464,10 @@ export class Infusionsoft implements INodeType {
|
||||||
qs.until = options.until as string;
|
qs.until = options.until as string;
|
||||||
}
|
}
|
||||||
if (returnAll) {
|
if (returnAll) {
|
||||||
responseData = await infusionsoftApiRequestAllItems.call(this, 'contacts', 'GET', '/contacts', {}, qs);
|
responseData = await keapApiRequestAllItems.call(this, 'contacts', 'GET', '/contacts', {}, qs);
|
||||||
} else {
|
} else {
|
||||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', '/contacts', {}, qs);
|
responseData = await keapApiRequest.call(this, 'GET', '/contacts', {}, qs);
|
||||||
responseData = responseData.contacts;
|
responseData = responseData.contacts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,18 +487,18 @@ export class Infusionsoft implements INodeType {
|
||||||
additionalFields.type = pascalCase(additionalFields.type as string);
|
additionalFields.type = pascalCase(additionalFields.type as string);
|
||||||
}
|
}
|
||||||
Object.assign(body, additionalFields);
|
Object.assign(body, additionalFields);
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'POST', '/notes', body);
|
responseData = await keapApiRequest.call(this, 'POST', '/notes', body);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Note/deleteNoteUsingDELETE
|
//https://developer.infusionsoft.com/docs/rest/#!/Note/deleteNoteUsingDELETE
|
||||||
if (operation === 'delete') {
|
if (operation === 'delete') {
|
||||||
const noteId = this.getNodeParameter('noteId', i) as string;
|
const noteId = this.getNodeParameter('noteId', i) as string;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'DELETE', `/notes/${noteId}`);
|
responseData = await keapApiRequest.call(this, 'DELETE', `/notes/${noteId}`);
|
||||||
responseData = { success: true };
|
responseData = { success: true };
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Note/getNoteUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/Note/getNoteUsingGET
|
||||||
if (operation === 'get') {
|
if (operation === 'get') {
|
||||||
const noteId = this.getNodeParameter('noteId', i) as string;
|
const noteId = this.getNodeParameter('noteId', i) as string;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', `/notes/${noteId}`);
|
responseData = await keapApiRequest.call(this, 'GET', `/notes/${noteId}`);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Note/listNotesUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/Note/listNotesUsingGET
|
||||||
if (operation === 'getAll') {
|
if (operation === 'getAll') {
|
||||||
|
@ -507,10 +507,10 @@ export class Infusionsoft implements INodeType {
|
||||||
keysToSnakeCase(filters);
|
keysToSnakeCase(filters);
|
||||||
Object.assign(qs, filters);
|
Object.assign(qs, filters);
|
||||||
if (returnAll) {
|
if (returnAll) {
|
||||||
responseData = await infusionsoftApiRequestAllItems.call(this, 'notes', 'GET', '/notes', {}, qs);
|
responseData = await keapApiRequestAllItems.call(this, 'notes', 'GET', '/notes', {}, qs);
|
||||||
} else {
|
} else {
|
||||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', '/notes', {}, qs);
|
responseData = await keapApiRequest.call(this, 'GET', '/notes', {}, qs);
|
||||||
responseData = responseData.notes;
|
responseData = responseData.notes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -524,7 +524,7 @@ export class Infusionsoft implements INodeType {
|
||||||
additionalFields.type = pascalCase(additionalFields.type as string);
|
additionalFields.type = pascalCase(additionalFields.type as string);
|
||||||
}
|
}
|
||||||
Object.assign(body, additionalFields);
|
Object.assign(body, additionalFields);
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'PATCH', `/notes/${noteId}`, body);
|
responseData = await keapApiRequest.call(this, 'PATCH', `/notes/${noteId}`, body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (resource === 'contactTag') {
|
if (resource === 'contactTag') {
|
||||||
|
@ -535,14 +535,14 @@ export class Infusionsoft implements INodeType {
|
||||||
const body: IDataObject = {
|
const body: IDataObject = {
|
||||||
tagIds,
|
tagIds,
|
||||||
};
|
};
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'POST', `/contacts/${contactId}/tags`, body);
|
responseData = await keapApiRequest.call(this, 'POST', `/contacts/${contactId}/tags`, body);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Contact/removeTagsFromContactUsingDELETE_1
|
//https://developer.infusionsoft.com/docs/rest/#!/Contact/removeTagsFromContactUsingDELETE_1
|
||||||
if (operation === 'delete') {
|
if (operation === 'delete') {
|
||||||
const contactId = parseInt(this.getNodeParameter('contactId', i) as string, 10);
|
const contactId = parseInt(this.getNodeParameter('contactId', i) as string, 10);
|
||||||
const tagIds = this.getNodeParameter('tagIds', i) as string;
|
const tagIds = this.getNodeParameter('tagIds', i) as string;
|
||||||
qs.ids = tagIds;
|
qs.ids = tagIds;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'DELETE', `/contacts/${contactId}/tags`, {}, qs);
|
responseData = await keapApiRequest.call(this, 'DELETE', `/contacts/${contactId}/tags`, {}, qs);
|
||||||
responseData = { success: true };
|
responseData = { success: true };
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Contact/listAppliedTagsUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/Contact/listAppliedTagsUsingGET
|
||||||
|
@ -550,10 +550,10 @@ export class Infusionsoft implements INodeType {
|
||||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||||
const contactId = parseInt(this.getNodeParameter('contactId', i) as string, 10);
|
const contactId = parseInt(this.getNodeParameter('contactId', i) as string, 10);
|
||||||
if (returnAll) {
|
if (returnAll) {
|
||||||
responseData = await infusionsoftApiRequestAllItems.call(this, 'tags', 'GET', `/contacts/${contactId}/tags`, {}, qs);
|
responseData = await keapApiRequestAllItems.call(this, 'tags', 'GET', `/contacts/${contactId}/tags`, {}, qs);
|
||||||
} else {
|
} else {
|
||||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', `/contacts/${contactId}/tags`, {}, qs);
|
responseData = await keapApiRequest.call(this, 'GET', `/contacts/${contactId}/tags`, {}, qs);
|
||||||
responseData = responseData.tags;
|
responseData = responseData.tags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -583,18 +583,18 @@ export class Infusionsoft implements INodeType {
|
||||||
if (shippingAddress) {
|
if (shippingAddress) {
|
||||||
body.shipping_address = keysToSnakeCase(shippingAddress)[0] as IShippingAddress;
|
body.shipping_address = keysToSnakeCase(shippingAddress)[0] as IShippingAddress;
|
||||||
}
|
}
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'POST', '/orders', body);
|
responseData = await keapApiRequest.call(this, 'POST', '/orders', body);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/E-Commerce/deleteOrderUsingDELETE
|
//https://developer.infusionsoft.com/docs/rest/#!/E-Commerce/deleteOrderUsingDELETE
|
||||||
if (operation === 'delete') {
|
if (operation === 'delete') {
|
||||||
const orderId = parseInt(this.getNodeParameter('orderId', i) as string, 10);
|
const orderId = parseInt(this.getNodeParameter('orderId', i) as string, 10);
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'DELETE', `/orders/${orderId}`);
|
responseData = await keapApiRequest.call(this, 'DELETE', `/orders/${orderId}`);
|
||||||
responseData = { success: true };
|
responseData = { success: true };
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/E-Commerce/getOrderUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/E-Commerce/getOrderUsingGET
|
||||||
if (operation === 'get') {
|
if (operation === 'get') {
|
||||||
const orderId = parseInt(this.getNodeParameter('orderId', i) as string, 10);
|
const orderId = parseInt(this.getNodeParameter('orderId', i) as string, 10);
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'get', `/orders/${orderId}`);
|
responseData = await keapApiRequest.call(this, 'get', `/orders/${orderId}`);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/E-Commerce/listOrdersUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/E-Commerce/listOrdersUsingGET
|
||||||
if (operation === 'getAll') {
|
if (operation === 'getAll') {
|
||||||
|
@ -603,10 +603,10 @@ export class Infusionsoft implements INodeType {
|
||||||
keysToSnakeCase(options);
|
keysToSnakeCase(options);
|
||||||
Object.assign(qs, options);
|
Object.assign(qs, options);
|
||||||
if (returnAll) {
|
if (returnAll) {
|
||||||
responseData = await infusionsoftApiRequestAllItems.call(this, 'orders', 'GET', '/orders', {}, qs);
|
responseData = await keapApiRequestAllItems.call(this, 'orders', 'GET', '/orders', {}, qs);
|
||||||
} else {
|
} else {
|
||||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', '/orders', {}, qs);
|
responseData = await keapApiRequest.call(this, 'GET', '/orders', {}, qs);
|
||||||
responseData = responseData.orders;
|
responseData = responseData.orders;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -621,18 +621,18 @@ export class Infusionsoft implements INodeType {
|
||||||
};
|
};
|
||||||
keysToSnakeCase(additionalFields);
|
keysToSnakeCase(additionalFields);
|
||||||
Object.assign(body, additionalFields);
|
Object.assign(body, additionalFields);
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'POST', '/products', body);
|
responseData = await keapApiRequest.call(this, 'POST', '/products', body);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Product/deleteProductUsingDELETE
|
//https://developer.infusionsoft.com/docs/rest/#!/Product/deleteProductUsingDELETE
|
||||||
if (operation === 'delete') {
|
if (operation === 'delete') {
|
||||||
const productId = this.getNodeParameter('productId', i) as string;
|
const productId = this.getNodeParameter('productId', i) as string;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'DELETE', `/products/${productId}`);
|
responseData = await keapApiRequest.call(this, 'DELETE', `/products/${productId}`);
|
||||||
responseData = { success: true };
|
responseData = { success: true };
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Product/retrieveProductUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/Product/retrieveProductUsingGET
|
||||||
if (operation === 'get') {
|
if (operation === 'get') {
|
||||||
const productId = this.getNodeParameter('productId', i) as string;
|
const productId = this.getNodeParameter('productId', i) as string;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'get', `/products/${productId}`);
|
responseData = await keapApiRequest.call(this, 'get', `/products/${productId}`);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Product/listProductsUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/Product/listProductsUsingGET
|
||||||
if (operation === 'getAll') {
|
if (operation === 'getAll') {
|
||||||
|
@ -641,10 +641,10 @@ export class Infusionsoft implements INodeType {
|
||||||
keysToSnakeCase(filters);
|
keysToSnakeCase(filters);
|
||||||
Object.assign(qs, filters);
|
Object.assign(qs, filters);
|
||||||
if (returnAll) {
|
if (returnAll) {
|
||||||
responseData = await infusionsoftApiRequestAllItems.call(this, 'products', 'GET', '/products', {}, qs);
|
responseData = await keapApiRequestAllItems.call(this, 'products', 'GET', '/products', {}, qs);
|
||||||
} else {
|
} else {
|
||||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', '/products', {}, qs);
|
responseData = await keapApiRequest.call(this, 'GET', '/products', {}, qs);
|
||||||
responseData = responseData.products;
|
responseData = responseData.products;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -661,12 +661,12 @@ export class Infusionsoft implements INodeType {
|
||||||
};
|
};
|
||||||
Object.assign(body, additionalFields);
|
Object.assign(body, additionalFields);
|
||||||
keysToSnakeCase(body as IDataObject);
|
keysToSnakeCase(body as IDataObject);
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'POST', '/emails', body);
|
responseData = await keapApiRequest.call(this, 'POST', '/emails', body);
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Email/deleteEmailUsingDELETE
|
//https://developer.infusionsoft.com/docs/rest/#!/Email/deleteEmailUsingDELETE
|
||||||
if (operation === 'deleteRecord') {
|
if (operation === 'deleteRecord') {
|
||||||
const emailRecordId = parseInt(this.getNodeParameter('emailRecordId', i) as string, 10);
|
const emailRecordId = parseInt(this.getNodeParameter('emailRecordId', i) as string, 10);
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'DELETE', `/emails/${emailRecordId}`);
|
responseData = await keapApiRequest.call(this, 'DELETE', `/emails/${emailRecordId}`);
|
||||||
responseData = { success: true };
|
responseData = { success: true };
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/Email/listEmailsUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/Email/listEmailsUsingGET
|
||||||
|
@ -676,10 +676,10 @@ export class Infusionsoft implements INodeType {
|
||||||
keysToSnakeCase(filters);
|
keysToSnakeCase(filters);
|
||||||
Object.assign(qs, filters);
|
Object.assign(qs, filters);
|
||||||
if (returnAll) {
|
if (returnAll) {
|
||||||
responseData = await infusionsoftApiRequestAllItems.call(this, 'emails', 'GET', '/emails', {}, qs);
|
responseData = await keapApiRequestAllItems.call(this, 'emails', 'GET', '/emails', {}, qs);
|
||||||
} else {
|
} else {
|
||||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', '/emails', {}, qs);
|
responseData = await keapApiRequest.call(this, 'GET', '/emails', {}, qs);
|
||||||
responseData = responseData.emails;
|
responseData = responseData.emails;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -728,7 +728,7 @@ export class Infusionsoft implements INodeType {
|
||||||
body.attachments = attachments;
|
body.attachments = attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'POST', '/emails/queue', body);
|
responseData = await keapApiRequest.call(this, 'POST', '/emails/queue', body);
|
||||||
responseData = { success: true };
|
responseData = { success: true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -736,7 +736,7 @@ export class Infusionsoft implements INodeType {
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/File/deleteFileUsingDELETE
|
//https://developer.infusionsoft.com/docs/rest/#!/File/deleteFileUsingDELETE
|
||||||
if (operation === 'delete') {
|
if (operation === 'delete') {
|
||||||
const fileId = parseInt(this.getNodeParameter('fileId', i) as string, 10);
|
const fileId = parseInt(this.getNodeParameter('fileId', i) as string, 10);
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'DELETE', `/files/${fileId}`);
|
responseData = await keapApiRequest.call(this, 'DELETE', `/files/${fileId}`);
|
||||||
responseData = { success: true };
|
responseData = { success: true };
|
||||||
}
|
}
|
||||||
//https://developer.infusionsoft.com/docs/rest/#!/File/listFilesUsingGET
|
//https://developer.infusionsoft.com/docs/rest/#!/File/listFilesUsingGET
|
||||||
|
@ -755,10 +755,10 @@ export class Infusionsoft implements INodeType {
|
||||||
qs.viewable = (qs.viewable as string).toUpperCase();
|
qs.viewable = (qs.viewable as string).toUpperCase();
|
||||||
}
|
}
|
||||||
if (returnAll) {
|
if (returnAll) {
|
||||||
responseData = await infusionsoftApiRequestAllItems.call(this, 'files', 'GET', '/files', {}, qs);
|
responseData = await keapApiRequestAllItems.call(this, 'files', 'GET', '/files', {}, qs);
|
||||||
} else {
|
} else {
|
||||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'GET', '/files', {}, qs);
|
responseData = await keapApiRequest.call(this, 'GET', '/files', {}, qs);
|
||||||
responseData = responseData.files;
|
responseData = responseData.files;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -797,7 +797,7 @@ export class Infusionsoft implements INodeType {
|
||||||
body.file_name = fileName;
|
body.file_name = fileName;
|
||||||
body.file_data = fileData;
|
body.file_data = fileData;
|
||||||
}
|
}
|
||||||
responseData = await infusionsoftApiRequest.call(this, 'POST', '/files', body);
|
responseData = await keapApiRequest.call(this, 'POST', '/files', body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Array.isArray(responseData)) {
|
if (Array.isArray(responseData)) {
|
|
@ -13,31 +13,31 @@ import {
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
infusionsoftApiRequest,
|
keapApiRequest,
|
||||||
} from './GenericFunctions';
|
} from './GenericFunctions';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
titleCase,
|
titleCase,
|
||||||
} from 'change-case';
|
} from 'change-case';
|
||||||
|
|
||||||
export class InfusionsoftTrigger implements INodeType {
|
export class KeapTrigger implements INodeType {
|
||||||
description: INodeTypeDescription = {
|
description: INodeTypeDescription = {
|
||||||
displayName: 'Infusionsoft Trigger',
|
displayName: 'Keap Trigger',
|
||||||
name: 'infusionsoftTrigger',
|
name: 'keapTrigger',
|
||||||
icon: 'file:infusionsoft.png',
|
icon: 'file:keap.png',
|
||||||
group: ['trigger'],
|
group: ['trigger'],
|
||||||
version: 1,
|
version: 1,
|
||||||
subtitle: '={{$parameter["eventId"]}}',
|
subtitle: '={{$parameter["eventId"]}}',
|
||||||
description: 'Starts the workflow when Infusionsoft events occure.',
|
description: 'Starts the workflow when Infusionsoft events occure.',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: 'Infusionsoft Trigger',
|
name: 'Keap Trigger',
|
||||||
color: '#79af53',
|
color: '#79af53',
|
||||||
},
|
},
|
||||||
inputs: [],
|
inputs: [],
|
||||||
outputs: ['main'],
|
outputs: ['main'],
|
||||||
credentials: [
|
credentials: [
|
||||||
{
|
{
|
||||||
name: 'infusionsoftOAuth2Api',
|
name: 'keapOAuth2Api',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -76,7 +76,7 @@ export class InfusionsoftTrigger implements INodeType {
|
||||||
// select them easily
|
// select them easily
|
||||||
async getEvents(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
async getEvents(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
const returnData: INodePropertyOptions[] = [];
|
const returnData: INodePropertyOptions[] = [];
|
||||||
const hooks = await infusionsoftApiRequest.call(this, 'GET', '/hooks/event_keys');
|
const hooks = await keapApiRequest.call(this, 'GET', '/hooks/event_keys');
|
||||||
for (const hook of hooks) {
|
for (const hook of hooks) {
|
||||||
const hookName = hook;
|
const hookName = hook;
|
||||||
const hookId = hook;
|
const hookId = hook;
|
||||||
|
@ -98,7 +98,7 @@ export class InfusionsoftTrigger implements INodeType {
|
||||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||||
const webhookData = this.getWorkflowStaticData('node');
|
const webhookData = this.getWorkflowStaticData('node');
|
||||||
|
|
||||||
const responseData = await infusionsoftApiRequest.call(this, 'GET', '/hooks', {});
|
const responseData = await keapApiRequest.call(this, 'GET', '/hooks', {});
|
||||||
|
|
||||||
for (const existingData of responseData) {
|
for (const existingData of responseData) {
|
||||||
if (existingData.hookUrl === webhookUrl
|
if (existingData.hookUrl === webhookUrl
|
||||||
|
@ -122,7 +122,7 @@ export class InfusionsoftTrigger implements INodeType {
|
||||||
hookUrl: webhookUrl,
|
hookUrl: webhookUrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
const responseData = await infusionsoftApiRequest.call(this, 'POST', '/hooks', body);
|
const responseData = await keapApiRequest.call(this, 'POST', '/hooks', body);
|
||||||
|
|
||||||
if (responseData.key === undefined) {
|
if (responseData.key === undefined) {
|
||||||
// Required data is missing so was not successful
|
// Required data is missing so was not successful
|
||||||
|
@ -139,7 +139,7 @@ export class InfusionsoftTrigger implements INodeType {
|
||||||
if (webhookData.webhookId !== undefined) {
|
if (webhookData.webhookId !== undefined) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await infusionsoftApiRequest.call(this, 'DELETE', `/hooks/${webhookData.webhookId}`);
|
await keapApiRequest.call(this, 'DELETE', `/hooks/${webhookData.webhookId}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
@ -50,8 +50,8 @@
|
||||||
"dist/credentials/HubspotApi.credentials.js",
|
"dist/credentials/HubspotApi.credentials.js",
|
||||||
"dist/credentials/Imap.credentials.js",
|
"dist/credentials/Imap.credentials.js",
|
||||||
"dist/credentials/IntercomApi.credentials.js",
|
"dist/credentials/IntercomApi.credentials.js",
|
||||||
"dist/credentials/InfusionsoftOAuth2Api.credentials.js",
|
|
||||||
"dist/credentials/JiraSoftwareCloudApi.credentials.js",
|
"dist/credentials/JiraSoftwareCloudApi.credentials.js",
|
||||||
|
"dist/credentials/KeapOAuth2Api.credentials.js",
|
||||||
"dist/credentials/LinkFishApi.credentials.js",
|
"dist/credentials/LinkFishApi.credentials.js",
|
||||||
"dist/credentials/MailchimpApi.credentials.js",
|
"dist/credentials/MailchimpApi.credentials.js",
|
||||||
"dist/credentials/MailgunApi.credentials.js",
|
"dist/credentials/MailgunApi.credentials.js",
|
||||||
|
@ -129,9 +129,9 @@
|
||||||
"dist/nodes/If.node.js",
|
"dist/nodes/If.node.js",
|
||||||
"dist/nodes/Interval.node.js",
|
"dist/nodes/Interval.node.js",
|
||||||
"dist/nodes/Intercom/Intercom.node.js",
|
"dist/nodes/Intercom/Intercom.node.js",
|
||||||
"dist/nodes/Infusionsoft/Infusionsoft.node.js",
|
|
||||||
"dist/nodes/Infusionsoft/InfusionsoftTrigger.node.js",
|
|
||||||
"dist/nodes/Jira/JiraSoftwareCloud.node.js",
|
"dist/nodes/Jira/JiraSoftwareCloud.node.js",
|
||||||
|
"dist/nodes/Keap/Keap.node.js",
|
||||||
|
"dist/nodes/Keap/KeapTrigger.node.js",
|
||||||
"dist/nodes/LinkFish/LinkFish.node.js",
|
"dist/nodes/LinkFish/LinkFish.node.js",
|
||||||
"dist/nodes/Mailchimp/Mailchimp.node.js",
|
"dist/nodes/Mailchimp/Mailchimp.node.js",
|
||||||
"dist/nodes/Mailchimp/MailchimpTrigger.node.js",
|
"dist/nodes/Mailchimp/MailchimpTrigger.node.js",
|
||||||
|
|
Loading…
Reference in a new issue