mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 12:44:07 -08:00
61e26804ba
* ⚡ enabled array-type * ⚡ await-thenable on * ⚡ ban-types on * ⚡ default-param-last on * ⚡ dot-notation on * ⚡ member-delimiter-style on * ⚡ no-duplicate-imports on * ⚡ no-empty-interface on * ⚡ no-floating-promises on * ⚡ no-for-in-array on * ⚡ no-invalid-void-type on * ⚡ no-loop-func on * ⚡ no-shadow on * ⚡ ban-ts-comment re enabled * ⚡ @typescript-eslint/lines-between-class-members on * address my own comment * @typescript-eslint/return-await on * @typescript-eslint/promise-function-async on * @typescript-eslint/no-unnecessary-boolean-literal-compare on * @typescript-eslint/no-unnecessary-type-assertion on * prefer-const on * @typescript-eslint/prefer-optional-chain on Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
314 lines
7.6 KiB
TypeScript
314 lines
7.6 KiB
TypeScript
import { IExecuteFunctions } from 'n8n-core';
|
|
|
|
import { IDataObject, ILoadOptionsFunctions } from 'n8n-workflow';
|
|
|
|
import { OptionsWithUri } from 'request';
|
|
|
|
import { flow, omit } from 'lodash';
|
|
|
|
import {
|
|
AllFieldsUi,
|
|
FieldWithPrimaryField,
|
|
LinksFieldContainer,
|
|
PersonResponse,
|
|
PetitionResponse,
|
|
Resource,
|
|
Response,
|
|
} from './types';
|
|
|
|
export async function actionNetworkApiRequest(
|
|
this: IExecuteFunctions | ILoadOptionsFunctions,
|
|
method: string,
|
|
endpoint: string,
|
|
body: IDataObject = {},
|
|
qs: IDataObject = {},
|
|
) {
|
|
const options: OptionsWithUri = {
|
|
method,
|
|
body,
|
|
qs,
|
|
uri: `https://actionnetwork.org/api/v2${endpoint}`,
|
|
json: true,
|
|
};
|
|
|
|
if (!Object.keys(body).length) {
|
|
delete options.body;
|
|
}
|
|
|
|
if (!Object.keys(qs).length) {
|
|
delete options.qs;
|
|
}
|
|
|
|
return this.helpers.requestWithAuthentication.call(this, 'actionNetworkApi', options);
|
|
}
|
|
|
|
export async function handleListing(
|
|
this: IExecuteFunctions | ILoadOptionsFunctions,
|
|
method: string,
|
|
endpoint: string,
|
|
body: IDataObject = {},
|
|
qs: IDataObject = {},
|
|
options?: { returnAll: true },
|
|
) {
|
|
const returnData: IDataObject[] = [];
|
|
let responseData;
|
|
|
|
qs.perPage = 25; // max
|
|
qs.page = 1;
|
|
|
|
const returnAll = options?.returnAll ?? (this.getNodeParameter('returnAll', 0, false) as boolean);
|
|
const limit = this.getNodeParameter('limit', 0, 0) as number;
|
|
|
|
const itemsKey = toItemsKey(endpoint);
|
|
|
|
do {
|
|
responseData = await actionNetworkApiRequest.call(this, method, endpoint, body, qs);
|
|
const items = responseData._embedded[itemsKey];
|
|
returnData.push(...items);
|
|
|
|
if (!returnAll && returnData.length >= limit) {
|
|
return returnData.slice(0, limit);
|
|
}
|
|
|
|
if (responseData._links?.next?.href) {
|
|
const queryString = new URLSearchParams(responseData._links.next.href.split('?')[1]);
|
|
qs.page = queryString.get('page') as string;
|
|
}
|
|
} while (responseData._links?.next);
|
|
|
|
return returnData;
|
|
}
|
|
|
|
// ----------------------------------------
|
|
// helpers
|
|
// ----------------------------------------
|
|
|
|
/**
|
|
* Convert an endpoint to the key needed to access data in the response.
|
|
*/
|
|
const toItemsKey = (endpoint: string) => {
|
|
// handle two-resource endpoint
|
|
if (
|
|
endpoint.includes('/signatures') ||
|
|
endpoint.includes('/attendances') ||
|
|
endpoint.includes('/taggings')
|
|
) {
|
|
endpoint = endpoint.split('/').pop()!;
|
|
}
|
|
|
|
return `osdi:${endpoint.replace(/\//g, '')}`;
|
|
};
|
|
|
|
export const extractId = (response: LinksFieldContainer) => {
|
|
return response._links.self.href.split('/').pop() ?? 'No ID';
|
|
};
|
|
|
|
export const makeOsdiLink = (personId: string) => {
|
|
return {
|
|
_links: {
|
|
'osdi:person': {
|
|
href: `https://actionnetwork.org/api/v2/people/${personId}`,
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
export const isPrimary = (field: FieldWithPrimaryField) => field.primary;
|
|
|
|
// ----------------------------------------
|
|
// field adjusters
|
|
// ----------------------------------------
|
|
|
|
function adjustLanguagesSpoken(allFields: AllFieldsUi) {
|
|
if (!allFields.languages_spoken) return allFields;
|
|
|
|
return {
|
|
...omit(allFields, ['languages_spoken']),
|
|
languages_spoken: [allFields.languages_spoken],
|
|
};
|
|
}
|
|
|
|
function adjustPhoneNumbers(allFields: AllFieldsUi) {
|
|
if (!allFields.phone_numbers) return allFields;
|
|
|
|
return {
|
|
...omit(allFields, ['phone_numbers']),
|
|
phone_numbers: [allFields.phone_numbers.phone_numbers_fields],
|
|
};
|
|
}
|
|
|
|
function adjustPostalAddresses(allFields: AllFieldsUi) {
|
|
if (!allFields.postal_addresses) return allFields;
|
|
|
|
if (allFields.postal_addresses.postal_addresses_fields.length) {
|
|
const adjusted = allFields.postal_addresses.postal_addresses_fields.map((field) => {
|
|
const copy: IDataObject = {
|
|
...omit(field, ['address_lines', 'location']),
|
|
};
|
|
|
|
if (field.address_lines) {
|
|
copy.address_lines = [field.address_lines];
|
|
}
|
|
|
|
if (field.location) {
|
|
copy.location = field.location.location_fields;
|
|
}
|
|
|
|
return copy;
|
|
});
|
|
|
|
return {
|
|
...omit(allFields, ['postal_addresses']),
|
|
postal_addresses: adjusted,
|
|
};
|
|
}
|
|
}
|
|
|
|
function adjustLocation(allFields: AllFieldsUi) {
|
|
if (!allFields.location) return allFields;
|
|
|
|
const locationFields = allFields.location.postal_addresses_fields;
|
|
|
|
const adjusted: IDataObject = {
|
|
...omit(locationFields, ['address_lines', 'location']),
|
|
};
|
|
|
|
if (locationFields.address_lines) {
|
|
adjusted.address_lines = [locationFields.address_lines];
|
|
}
|
|
|
|
if (locationFields.location) {
|
|
adjusted.location = locationFields.location.location_fields;
|
|
}
|
|
|
|
return {
|
|
...omit(allFields, ['location']),
|
|
location: adjusted,
|
|
};
|
|
}
|
|
|
|
function adjustTargets(allFields: AllFieldsUi) {
|
|
if (!allFields.target) return allFields;
|
|
|
|
const adjusted = allFields.target.split(',').map((value) => ({ name: value }));
|
|
|
|
return {
|
|
...omit(allFields, ['target']),
|
|
target: adjusted,
|
|
};
|
|
}
|
|
|
|
// ----------------------------------------
|
|
// payload adjusters
|
|
// ----------------------------------------
|
|
|
|
export const adjustPersonPayload = flow(
|
|
adjustLanguagesSpoken,
|
|
adjustPhoneNumbers,
|
|
adjustPostalAddresses,
|
|
);
|
|
|
|
export const adjustPetitionPayload = adjustTargets;
|
|
|
|
export const adjustEventPayload = adjustLocation;
|
|
|
|
// ----------------------------------------
|
|
// resource loaders
|
|
// ----------------------------------------
|
|
|
|
async function loadResource(this: ILoadOptionsFunctions, resource: string) {
|
|
return handleListing.call(this, 'GET', `/${resource}`, {}, {}, { returnAll: true });
|
|
}
|
|
|
|
export const resourceLoaders = {
|
|
async getTags(this: ILoadOptionsFunctions) {
|
|
const tags = (await loadResource.call(this, 'tags')) as Array<
|
|
{ name: string } & LinksFieldContainer
|
|
>;
|
|
|
|
return tags.map((tag) => ({ name: tag.name, value: extractId(tag) }));
|
|
},
|
|
|
|
async getTaggings(this: ILoadOptionsFunctions) {
|
|
const tagId = this.getNodeParameter('tagId', 0);
|
|
const endpoint = `/tags/${tagId}/taggings`;
|
|
|
|
// two-resource endpoint, so direct call
|
|
const taggings = (await handleListing.call(
|
|
this,
|
|
'GET',
|
|
endpoint,
|
|
{},
|
|
{},
|
|
{ returnAll: true },
|
|
)) as LinksFieldContainer[];
|
|
|
|
return taggings.map((tagging) => {
|
|
const taggingId = extractId(tagging);
|
|
|
|
return {
|
|
name: taggingId,
|
|
value: taggingId,
|
|
};
|
|
});
|
|
},
|
|
};
|
|
|
|
// ----------------------------------------
|
|
// response simplifiers
|
|
// ----------------------------------------
|
|
|
|
export const simplifyResponse = (response: Response, resource: Resource) => {
|
|
if (resource === 'person') {
|
|
return simplifyPersonResponse(response as PersonResponse);
|
|
} else if (resource === 'petition') {
|
|
return simplifyPetitionResponse(response as PetitionResponse);
|
|
}
|
|
|
|
const fieldsToSimplify = ['identifiers', '_links', 'action_network:sponsor', 'reminders'];
|
|
|
|
return {
|
|
id: extractId(response),
|
|
...omit(response, fieldsToSimplify),
|
|
};
|
|
};
|
|
|
|
const simplifyPetitionResponse = (response: PetitionResponse) => {
|
|
const fieldsToSimplify = ['identifiers', '_links', 'action_network:hidden', '_embedded'];
|
|
|
|
return {
|
|
id: extractId(response),
|
|
...omit(response, fieldsToSimplify),
|
|
creator: simplifyPersonResponse(response._embedded['osdi:creator']),
|
|
};
|
|
};
|
|
|
|
const simplifyPersonResponse = (response: PersonResponse) => {
|
|
const emailAddress = response.email_addresses.filter(isPrimary);
|
|
const phoneNumber = response.phone_numbers.filter(isPrimary);
|
|
const postalAddress = response.postal_addresses.filter(isPrimary);
|
|
|
|
const fieldsToSimplify = [
|
|
'identifiers',
|
|
'email_addresses',
|
|
'phone_numbers',
|
|
'postal_addresses',
|
|
'languages_spoken',
|
|
'_links',
|
|
];
|
|
|
|
return {
|
|
id: extractId(response),
|
|
...omit(response, fieldsToSimplify),
|
|
...{ email_address: emailAddress[0].address || '' },
|
|
...{ phone_number: phoneNumber[0].number || '' },
|
|
...{
|
|
postal_address: {
|
|
...(postalAddress && omit(postalAddress[0], 'address_lines')),
|
|
address_lines: postalAddress[0].address_lines ?? '',
|
|
},
|
|
},
|
|
language_spoken: response.languages_spoken[0],
|
|
};
|
|
};
|