n8n/packages/nodes-base/nodes/Google/MyBusiness/GoogleMyBusinessTrigger.node.ts
2024-10-16 16:18:53 +01:00

193 lines
4.9 KiB
TypeScript

import {
NodeApiError,
NodeConnectionType,
type IPollFunctions,
type IDataObject,
type INodeExecutionData,
type INodeType,
type INodeTypeDescription,
} from 'n8n-workflow';
import { googleApiRequest, searchAccounts, searchLocations } from './GenericFunctions';
export class GoogleMyBusinessTrigger implements INodeType {
description: INodeTypeDescription = {
displayName: 'Google My Business Trigger',
name: 'googleMyBusinessTrigger',
icon: 'file:googleMyBusines.svg',
group: ['trigger'],
version: 1,
description:
'Fetches reviews from Google My Business and starts the workflow on specified polling intervals.',
subtitle: '={{"Google My Business Trigger"}}',
defaults: {
name: 'Google My Business Trigger',
},
credentials: [
{
name: 'googleMyBusinessOAuth2Api',
required: true,
},
],
polling: true,
inputs: [],
outputs: [NodeConnectionType.Main],
properties: [
{
displayName: 'Event',
name: 'event',
required: true,
type: 'options',
noDataExpression: true,
default: 'reviewAdded',
options: [
{
name: 'Review Added',
value: 'reviewAdded',
},
],
},
{
displayName: 'Account',
name: 'account',
required: true,
type: 'resourceLocator',
default: { mode: 'list', value: '' },
description: 'The Google My Business account',
displayOptions: { show: { event: ['reviewAdded'] } },
modes: [
{
displayName: 'From list',
name: 'list',
type: 'list',
typeOptions: {
searchListMethod: 'searchAccounts',
searchable: true,
},
},
{
displayName: 'By name',
name: 'name',
type: 'string',
hint: 'Enter the account name',
validation: [
{
type: 'regex',
properties: {
regex: 'accounts/[0-9]+',
errorMessage: 'The name must start with "accounts/"',
},
},
],
placeholder: 'e.g. accounts/0123456789',
},
],
},
{
displayName: 'Location',
name: 'location',
required: true,
type: 'resourceLocator',
default: { mode: 'list', value: '' },
description: 'The specific location or business associated with the account',
displayOptions: { show: { event: ['reviewAdded'] } },
modes: [
{
displayName: 'From list',
name: 'list',
type: 'list',
typeOptions: {
searchListMethod: 'searchLocations',
searchable: true,
},
},
{
displayName: 'By name',
name: 'name',
type: 'string',
hint: 'Enter the location name',
validation: [
{
type: 'regex',
properties: {
regex: 'locations/[0-9]+',
errorMessage: 'The name must start with "locations/"',
},
},
],
placeholder: 'e.g. locations/0123456789',
},
],
},
],
};
methods = {
listSearch: {
searchAccounts,
searchLocations,
},
};
async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
const nodeStaticData = this.getWorkflowStaticData('node');
let responseData;
const qs: IDataObject = {};
const account = (this.getNodeParameter('account') as { value: string; mode: string }).value;
const location = (this.getNodeParameter('location') as { value: string; mode: string }).value;
const manualMode = this.getMode() === 'manual';
if (manualMode) {
qs.pageSize = 1; // In manual mode we only want to fetch the latest review
} else {
qs.pageSize = 50; // Maximal page size for the get reviews endpoint
}
try {
responseData = (await googleApiRequest.call(
this,
'GET',
`/${account}/${location}/reviews`,
{},
qs,
)) as { reviews: IDataObject[]; totalReviewCount: number; nextPageToken?: string };
if (manualMode) {
responseData = responseData.reviews;
} else {
// During the first execution there is no delta
if (!nodeStaticData.totalReviewCountLastTimeChecked) {
nodeStaticData.totalReviewCountLastTimeChecked = responseData.totalReviewCount;
return null;
}
// When count did't change the node shouldn't trigger
if (
!responseData?.reviews?.length ||
nodeStaticData?.totalReviewCountLastTimeChecked === responseData?.totalReviewCount
) {
return null;
}
const numNewReviews =
// @ts-ignore
responseData.totalReviewCount - nodeStaticData.totalReviewCountLastTimeChecked;
nodeStaticData.totalReviewCountLastTimeChecked = responseData.totalReviewCount;
// By default the reviews will be sorted by updateTime in descending order
// Return only the delta reviews since last pooling
responseData = responseData.reviews.slice(0, numNewReviews);
}
if (Array.isArray(responseData) && responseData.length) {
return [this.helpers.returnJsonArray(responseData)];
}
return null;
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
}
}