From b0703247c28a6c2d486d3c3b05bde1ba0876681b Mon Sep 17 00:00:00 2001 From: Marcus Date: Tue, 17 Jan 2023 16:45:01 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=90=9B=20fix=20create=20database=20pa?= =?UTF-8?q?ge=20fails=20if=20relation=20param=20is=20empty/undefined?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/nodes-base/nodes/Notion/GenericFunctions.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/nodes-base/nodes/Notion/GenericFunctions.ts b/packages/nodes-base/nodes/Notion/GenericFunctions.ts index 53c00cf725d04..9a9e61213468b 100644 --- a/packages/nodes-base/nodes/Notion/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Notion/GenericFunctions.ts @@ -289,10 +289,13 @@ function getPropertyKeyValue(value: any, type: string, timezone: string, version case 'relation': result = { type: 'relation', - - relation: value.relationValue.reduce((acc: [], cur: any) => { - return acc.concat(cur.split(',').map((relation: string) => ({ id: relation.trim() }))); - }, []), + relation: value.relationValue + .filter((rv: string) => { + return rv && typeof rv === 'string'; + }) + .reduce((acc: [], cur: any) => { + return acc.concat(cur.split(',').map((relation: string) => ({ id: relation.trim() }))); + }, []), }; break; case 'multi_select': From 3f104b8e7f57aafdfd193b716c4b04edcf68cb70 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Wed, 18 Jan 2023 10:11:25 +0200 Subject: [PATCH 2/3] :zap: uuid validation --- .../nodes-base/nodes/Notion/GenericFunctions.ts | 17 +++++++++++++---- .../nodes-base/nodes/Notion/v2/NotionV2.node.ts | 4 ++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/nodes-base/nodes/Notion/GenericFunctions.ts b/packages/nodes-base/nodes/Notion/GenericFunctions.ts index 9a9e61213468b..bbb52d871597e 100644 --- a/packages/nodes-base/nodes/Notion/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Notion/GenericFunctions.ts @@ -25,6 +25,17 @@ import moment from 'moment-timezone'; import { validate as uuidValidate } from 'uuid'; +const uuidValidateWithoutDashes = (value: string) => { + if (!value || typeof value !== 'string') return false; + if (uuidValidate(value)) return true; + if (value.length !== 32) return false; + //prettier-ignore + const strWithDashes = `${value.slice(0, 8)}-${value.slice(8, 12)}-${value.slice(12, 16)}-${value.slice(16, 20)}-${value.slice(20)}`; + return uuidValidate(strWithDashes); +}; + +export type SortData = { key: string; type: string; direction: string; timestamp: boolean }; + const apiVersion: { [key: number]: string } = { 1: '2021-05-13', 2: '2021-08-16', @@ -291,7 +302,7 @@ function getPropertyKeyValue(value: any, type: string, timezone: string, version type: 'relation', relation: value.relationValue .filter((rv: string) => { - return rv && typeof rv === 'string'; + return uuidValidateWithoutDashes(rv); }) .reduce((acc: [], cur: any) => { return acc.concat(cur.split(',').map((relation: string) => ({ id: relation.trim() }))); @@ -418,9 +429,7 @@ export function mapProperties(properties: IDataObject[], timezone: string, versi ); } -export function mapSorting( - data: [{ key: string; type: string; direction: string; timestamp: boolean }], -) { +export function mapSorting(data: SortData[]) { return data.map((sort) => { return { direction: sort.direction, diff --git a/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts b/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts index 0fc5916d83467..4d1d480bc69c3 100644 --- a/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts +++ b/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts @@ -26,6 +26,7 @@ import { notionApiRequest, notionApiRequestAllItems, simplifyObjects, + SortData, validateJSON, } from '../GenericFunctions'; @@ -536,8 +537,7 @@ export class NotionV2 implements INodeType { delete body.filter; } if (sort) { - //@ts-expect-error - body.sorts = mapSorting(sort); + body.sorts = mapSorting(sort as SortData[]); } if (returnAll) { responseData = await notionApiRequestAllItems.call( From c04e8b798844dedfe95ed74f4129597fd5b2cd7e Mon Sep 17 00:00:00 2001 From: Marcus Date: Wed, 18 Jan 2023 12:53:53 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9A=A1=20uuid=20error=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nodes/Notion/GenericFunctions.ts | 37 ++++++++++++++----- .../nodes/Notion/v1/NotionV1.node.ts | 4 +- .../nodes/Notion/v2/NotionV2.node.ts | 4 +- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/packages/nodes-base/nodes/Notion/GenericFunctions.ts b/packages/nodes-base/nodes/Notion/GenericFunctions.ts index bbb52d871597e..8fe344a34bea0 100644 --- a/packages/nodes-base/nodes/Notion/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Notion/GenericFunctions.ts @@ -15,6 +15,7 @@ import { INodeProperties, IPollFunctions, NodeApiError, + NodeOperationError, } from 'n8n-workflow'; import { camelCase, capitalCase, snakeCase } from 'change-case'; @@ -25,14 +26,19 @@ import moment from 'moment-timezone'; import { validate as uuidValidate } from 'uuid'; -const uuidValidateWithoutDashes = (value: string) => { +function uuidValidateWithoutDashes(this: IExecuteFunctions, value: string) { if (!value || typeof value !== 'string') return false; if (uuidValidate(value)) return true; - if (value.length !== 32) return false; - //prettier-ignore - const strWithDashes = `${value.slice(0, 8)}-${value.slice(8, 12)}-${value.slice(12, 16)}-${value.slice(16, 20)}-${value.slice(20)}`; - return uuidValidate(strWithDashes); -}; + if (value.length == 32) { + //prettier-ignore + const strWithDashes = `${value.slice(0, 8)}-${value.slice(8, 12)}-${value.slice(12, 16)}-${value.slice(16, 20)}-${value.slice(20)}`; + if (uuidValidate(strWithDashes)) return true; + } + throw new NodeOperationError( + this.getNode(), + `The relation id "${value}" is not a valid uuid with optional dashes.`, + ); +} export type SortData = { key: string; type: string; direction: string; timestamp: boolean }; @@ -272,7 +278,13 @@ function getDateFormat(includeTime: boolean) { return ''; } -function getPropertyKeyValue(value: any, type: string, timezone: string, version = 1) { +function getPropertyKeyValue( + this: IExecuteFunctions, + value: any, + type: string, + timezone: string, + version = 1, +) { const ignoreIfEmpty = (v: T, cb: (v: T) => any) => !v && value.ignoreIfEmpty ? undefined : cb(v); let result: IDataObject = {}; @@ -302,7 +314,7 @@ function getPropertyKeyValue(value: any, type: string, timezone: string, version type: 'relation', relation: value.relationValue .filter((rv: string) => { - return uuidValidateWithoutDashes(rv); + return uuidValidateWithoutDashes.call(this, rv); }) .reduce((acc: [], cur: any) => { return acc.concat(cur.split(',').map((relation: string) => ({ id: relation.trim() }))); @@ -406,7 +418,12 @@ function getNameAndType(key: string) { }; } -export function mapProperties(properties: IDataObject[], timezone: string, version = 1) { +export function mapProperties( + this: IExecuteFunctions, + properties: IDataObject[], + timezone: string, + version = 1, +) { return properties .filter( (property): property is Record => @@ -416,7 +433,7 @@ export function mapProperties(properties: IDataObject[], timezone: string, versi (property) => [ `${property.key.split('|')[0]}`, - getPropertyKeyValue(property, property.key.split('|')[1], timezone, version), + getPropertyKeyValue.call(this, property, property.key.split('|')[1], timezone, version), ] as const, ) .filter(([, value]) => value) diff --git a/packages/nodes-base/nodes/Notion/v1/NotionV1.node.ts b/packages/nodes-base/nodes/Notion/v1/NotionV1.node.ts index 35678ecdbdfa8..a7de180182a02 100644 --- a/packages/nodes-base/nodes/Notion/v1/NotionV1.node.ts +++ b/packages/nodes-base/nodes/Notion/v1/NotionV1.node.ts @@ -359,7 +359,7 @@ export class NotionV1 implements INodeType { [], ) as IDataObject[]; if (properties.length !== 0) { - body.properties = mapProperties(properties, timezone) as IDataObject; + body.properties = mapProperties.call(this, properties, timezone) as IDataObject; } const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[]; extractDatabaseMentionRLC(blockValues); @@ -460,7 +460,7 @@ export class NotionV1 implements INodeType { properties: {}, }; if (properties.length !== 0) { - body.properties = mapProperties(properties, timezone) as IDataObject; + body.properties = mapProperties.call(this, properties, timezone) as IDataObject; } responseData = await notionApiRequest.call(this, 'PATCH', `/pages/${pageId}`, body); if (simple) { diff --git a/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts b/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts index 4d1d480bc69c3..1d1173e61323f 100644 --- a/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts +++ b/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts @@ -458,7 +458,7 @@ export class NotionV2 implements INodeType { if (propertiesValues.length !== 0) { body.properties = Object.assign( body.properties, - mapProperties(propertiesValues, timezone, 2) as IDataObject, + mapProperties.call(this, propertiesValues, timezone, 2) as IDataObject, ); } const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[]; @@ -590,7 +590,7 @@ export class NotionV2 implements INodeType { properties: {}, }; if (properties.length !== 0) { - body.properties = mapProperties(properties, timezone, 2) as IDataObject; + body.properties = mapProperties.call(this, properties, timezone, 2) as IDataObject; } responseData = await notionApiRequest.call(this, 'PATCH', `/pages/${pageId}`, body); if (simple) {