From a1f6c570d63a8acd7b623fb039bfdbcd017dc022 Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Wed, 13 Mar 2024 13:57:17 +0200 Subject: [PATCH] fix(Notion Node): Regex for block id (#8860) --- .../nodes-base/nodes/Notion/Notion.node.ts | 3 +- .../nodes/Notion/shared/GenericFunctions.ts | 42 +++++++++++ .../shared/descriptions/BlockDescription.ts | 75 +++++++++++++++++++ .../nodes/Notion/v2/NotionV2.node.ts | 12 +-- .../nodes/Notion/v2/VersionDescription.ts | 2 +- 5 files changed, 124 insertions(+), 10 deletions(-) diff --git a/packages/nodes-base/nodes/Notion/Notion.node.ts b/packages/nodes-base/nodes/Notion/Notion.node.ts index 293c386ec0..7601a89867 100644 --- a/packages/nodes-base/nodes/Notion/Notion.node.ts +++ b/packages/nodes-base/nodes/Notion/Notion.node.ts @@ -13,13 +13,14 @@ export class Notion extends VersionedNodeType { group: ['output'], subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Consume Notion API', - defaultVersion: 2.1, + defaultVersion: 2.2, }; const nodeVersions: IVersionedNodeType['nodeVersions'] = { 1: new NotionV1(baseDescription), 2: new NotionV2(baseDescription), 2.1: new NotionV2(baseDescription), + 2.2: new NotionV2(baseDescription), }; super(nodeVersions, baseDescription); diff --git a/packages/nodes-base/nodes/Notion/shared/GenericFunctions.ts b/packages/nodes-base/nodes/Notion/shared/GenericFunctions.ts index e484970731..bc5bd09fe5 100644 --- a/packages/nodes-base/nodes/Notion/shared/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Notion/shared/GenericFunctions.ts @@ -41,6 +41,7 @@ const apiVersion: { [key: number]: string } = { 1: '2021-05-13', 2: '2021-08-16', 2.1: '2021-08-16', + 2.2: '2021-08-16', }; export async function notionApiRequest( @@ -1128,3 +1129,44 @@ export function simplifyBlocksOutput(blocks: IDataObject[], rootId: string) { return blocks; } + +export function extractBlockId(this: IExecuteFunctions, nodeVersion: number, itemIndex: number) { + let blockId: string; + + if (nodeVersion < 2.2) { + blockId = extractPageId( + this.getNodeParameter('blockId', itemIndex, '', { extractValue: true }) as string, + ); + } else { + const blockIdRLCData = this.getNodeParameter('blockId', itemIndex, {}) as IDataObject; + + if (blockIdRLCData.mode === 'id') { + blockId = blockIdRLCData.value as string; + } else { + const blockRegex = /https:\/\/www\.notion\.so\/.+\?pvs=[0-9]+#([a-f0-9]{2,})/; + const match = (blockIdRLCData.value as string).match(blockRegex); + + if (match === null) { + const pageRegex = + /(?:https|http):\/\/www\.notion\.so\/(?:[a-z0-9-]{2,}\/)?(?:[a-zA-Z0-9-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})/; + const pageMatch = (blockIdRLCData.value as string).match(pageRegex); + + if (pageMatch === null) { + throw new NodeOperationError( + this.getNode(), + 'Invalid URL, could not find block ID or page ID', + { + itemIndex, + }, + ); + } else { + blockId = extractPageId(pageMatch[1]); + } + } else { + blockId = match[1]; + } + } + } + + return blockId; +} diff --git a/packages/nodes-base/nodes/Notion/shared/descriptions/BlockDescription.ts b/packages/nodes-base/nodes/Notion/shared/descriptions/BlockDescription.ts index f8de52cada..fbb48ce26b 100644 --- a/packages/nodes-base/nodes/Notion/shared/descriptions/BlockDescription.ts +++ b/packages/nodes-base/nodes/Notion/shared/descriptions/BlockDescription.ts @@ -2,6 +2,55 @@ import type { INodeProperties } from 'n8n-workflow'; import { blocks } from './Blocks'; +//RLC with fixed regex for blockId +const blockIdRLC: INodeProperties = { + displayName: 'Block', + name: 'blockId', + type: 'resourceLocator', + default: { mode: 'url', value: '' }, + required: true, + modes: [ + { + displayName: 'Link', + name: 'url', + type: 'string', + placeholder: + 'e.g. https://www.notion.so/Block-Test-88888ccc303e4f44847f27d24bd7ad8e?pvs=4#c44444444444bbbbb4d32fdfdd84e', + validation: [ + { + type: 'regex', + properties: { + regex: + '(?:https|http)://www.notion.so/(?:[a-z0-9-]{2,}/)?(?:[a-zA-Z0-9-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*', + errorMessage: 'Not a valid Notion Block URL', + }, + }, + ], + // extractValue: { + // type: 'regex', + // regex: 'https:\\/\\/www\\.notion\\.so\\/.+\\?pvs=[0-9]+#([a-f0-9]{2,})', + // }, + }, + { + displayName: 'ID', + name: 'id', + type: 'string', + placeholder: 'e.g. ab1545b247fb49fa92d6f4b49f4d8116', + validation: [ + { + type: 'regex', + properties: { + regex: '[a-f0-9]{2,}', + errorMessage: 'Not a valid Notion Block ID', + }, + }, + ], + }, + ], + description: + "The Notion Block to get all children from, when using 'By URL' mode make sure to use the URL of the block itself, you can find it in block parameters in Notion under 'Copy link to block'", +}; + export const blockOperations: INodeProperties[] = [ { displayName: 'Operation', @@ -91,9 +140,22 @@ export const blockFields: INodeProperties[] = [ resource: ['block'], operation: ['append'], }, + hide: { + '@version': [{ _cnd: { gte: 2.2 } }], + }, }, description: 'The Notion Block to append blocks to', }, + { + ...blockIdRLC, + displayOptions: { + show: { + resource: ['block'], + operation: ['append'], + '@version': [{ _cnd: { gte: 2.2 } }], + }, + }, + }, ...blocks('block', 'append'), /* -------------------------------------------------------------------------- */ /* block:getAll */ @@ -153,9 +215,22 @@ export const blockFields: INodeProperties[] = [ resource: ['block'], operation: ['getAll'], }, + hide: { + '@version': [{ _cnd: { gte: 2.2 } }], + }, }, description: 'The Notion Block to get all children from', }, + { + ...blockIdRLC, + displayOptions: { + show: { + resource: ['block'], + operation: ['getAll'], + '@version': [{ _cnd: { gte: 2.2 } }], + }, + }, + }, { displayName: 'Return All', name: 'returnAll', diff --git a/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts b/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts index 09e67bc4ea..cdb290f93d 100644 --- a/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts +++ b/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts @@ -11,6 +11,7 @@ import { jsonParse, NodeApiError } from 'n8n-workflow'; import type { SortData, FileRecord } from '../shared/GenericFunctions'; import { downloadFiles, + extractBlockId, extractDatabaseId, extractDatabaseMentionRLC, extractPageId, @@ -45,6 +46,7 @@ export class NotionV2 implements INodeType { async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); + const nodeVersion = this.getNode().typeVersion; const resource = this.getNodeParameter('resource', 0); const operation = this.getNodeParameter('operation', 0); @@ -60,9 +62,7 @@ export class NotionV2 implements INodeType { if (operation === 'append') { for (let i = 0; i < itemsLength; i++) { try { - const blockId = extractPageId( - this.getNodeParameter('blockId', i, '', { extractValue: true }) as string, - ); + const blockId = extractBlockId.call(this, nodeVersion, i); const blockValues = this.getNodeParameter( 'blockUi.blockValues', i, @@ -100,9 +100,7 @@ export class NotionV2 implements INodeType { if (operation === 'getAll') { for (let i = 0; i < itemsLength; i++) { try { - const blockId = extractPageId( - this.getNodeParameter('blockId', i, '', { extractValue: true }) as string, - ); + const blockId = extractBlockId.call(this, nodeVersion, i); const returnAll = this.getNodeParameter('returnAll', i); const fetchNestedBlocks = this.getNodeParameter('fetchNestedBlocks', i) as boolean; @@ -148,8 +146,6 @@ export class NotionV2 implements INodeType { ..._data, })); - const nodeVersion = this.getNode().typeVersion; - if (nodeVersion > 2) { const simplifyOutput = this.getNodeParameter('simplifyOutput', i) as boolean; diff --git a/packages/nodes-base/nodes/Notion/v2/VersionDescription.ts b/packages/nodes-base/nodes/Notion/v2/VersionDescription.ts index 6e5c42c72b..0cdd099573 100644 --- a/packages/nodes-base/nodes/Notion/v2/VersionDescription.ts +++ b/packages/nodes-base/nodes/Notion/v2/VersionDescription.ts @@ -18,7 +18,7 @@ export const versionDescription: INodeTypeDescription = { name: 'notion', icon: 'file:notion.svg', group: ['output'], - version: [2, 2.1], + version: [2, 2.1, 2.2], subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Consume Notion API', defaults: {