diff --git a/packages/nodes-base/nodes/Notion/NotionTrigger.node.ts b/packages/nodes-base/nodes/Notion/NotionTrigger.node.ts index 5c3576402a..ca6c69aa86 100644 --- a/packages/nodes-base/nodes/Notion/NotionTrigger.node.ts +++ b/packages/nodes-base/nodes/Notion/NotionTrigger.node.ts @@ -7,9 +7,9 @@ import type { } from 'n8n-workflow'; import moment from 'moment-timezone'; -import { notionApiRequest, simplifyObjects } from './GenericFunctions'; +import { notionApiRequest, simplifyObjects } from './shared/GenericFunctions'; -import { getDatabases } from './SearchFunctions'; +import { listSearch } from './shared/methods'; export class NotionTrigger implements INodeType { description: INodeTypeDescription = { @@ -142,9 +142,7 @@ export class NotionTrigger implements INodeType { }; methods = { - listSearch: { - getDatabases, - }, + listSearch, }; async poll(this: IPollFunctions): Promise { diff --git a/packages/nodes-base/nodes/Notion/GenericFunctions.ts b/packages/nodes-base/nodes/Notion/shared/GenericFunctions.ts similarity index 99% rename from packages/nodes-base/nodes/Notion/GenericFunctions.ts rename to packages/nodes-base/nodes/Notion/shared/GenericFunctions.ts index c20a3b8de8..e484970731 100644 --- a/packages/nodes-base/nodes/Notion/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Notion/shared/GenericFunctions.ts @@ -20,7 +20,7 @@ import { camelCase, capitalCase, snakeCase } from 'change-case'; import moment from 'moment-timezone'; import { validate as uuidValidate } from 'uuid'; -import { filters } from './Filters'; +import { filters } from './descriptions/Filters'; function uuidValidateWithoutDashes(this: IExecuteFunctions, value: string) { if (uuidValidate(value)) return true; @@ -151,7 +151,7 @@ export async function notionApiRequestGetBlockChildrens( return responseData; } -export function getBlockTypes() { +export function getBlockTypesOptions() { return [ { name: 'Paragraph', diff --git a/packages/nodes-base/nodes/Notion/BlockDescription.ts b/packages/nodes-base/nodes/Notion/shared/descriptions/BlockDescription.ts similarity index 100% rename from packages/nodes-base/nodes/Notion/BlockDescription.ts rename to packages/nodes-base/nodes/Notion/shared/descriptions/BlockDescription.ts diff --git a/packages/nodes-base/nodes/Notion/Blocks.ts b/packages/nodes-base/nodes/Notion/shared/descriptions/Blocks.ts similarity index 100% rename from packages/nodes-base/nodes/Notion/Blocks.ts rename to packages/nodes-base/nodes/Notion/shared/descriptions/Blocks.ts diff --git a/packages/nodes-base/nodes/Notion/DatabaseDescription.ts b/packages/nodes-base/nodes/Notion/shared/descriptions/DatabaseDescription.ts similarity index 100% rename from packages/nodes-base/nodes/Notion/DatabaseDescription.ts rename to packages/nodes-base/nodes/Notion/shared/descriptions/DatabaseDescription.ts diff --git a/packages/nodes-base/nodes/Notion/DatabasePageDescription.ts b/packages/nodes-base/nodes/Notion/shared/descriptions/DatabasePageDescription.ts similarity index 99% rename from packages/nodes-base/nodes/Notion/DatabasePageDescription.ts rename to packages/nodes-base/nodes/Notion/shared/descriptions/DatabasePageDescription.ts index 6ecf6d7b94..4916a36223 100644 --- a/packages/nodes-base/nodes/Notion/DatabasePageDescription.ts +++ b/packages/nodes-base/nodes/Notion/shared/descriptions/DatabasePageDescription.ts @@ -1,6 +1,6 @@ import type { INodeProperties } from 'n8n-workflow'; -import { getConditions, getSearchFilters } from './GenericFunctions'; +import { getConditions, getSearchFilters } from '../GenericFunctions'; import { blocks, text } from './Blocks'; diff --git a/packages/nodes-base/nodes/Notion/Filters.ts b/packages/nodes-base/nodes/Notion/shared/descriptions/Filters.ts similarity index 100% rename from packages/nodes-base/nodes/Notion/Filters.ts rename to packages/nodes-base/nodes/Notion/shared/descriptions/Filters.ts diff --git a/packages/nodes-base/nodes/Notion/PageDescription.ts b/packages/nodes-base/nodes/Notion/shared/descriptions/PageDescription.ts similarity index 100% rename from packages/nodes-base/nodes/Notion/PageDescription.ts rename to packages/nodes-base/nodes/Notion/shared/descriptions/PageDescription.ts diff --git a/packages/nodes-base/nodes/Notion/UserDescription.ts b/packages/nodes-base/nodes/Notion/shared/descriptions/UserDescription.ts similarity index 100% rename from packages/nodes-base/nodes/Notion/UserDescription.ts rename to packages/nodes-base/nodes/Notion/shared/descriptions/UserDescription.ts diff --git a/packages/nodes-base/nodes/Notion/shared/methods/index.ts b/packages/nodes-base/nodes/Notion/shared/methods/index.ts new file mode 100644 index 0000000000..c7fb720e47 --- /dev/null +++ b/packages/nodes-base/nodes/Notion/shared/methods/index.ts @@ -0,0 +1 @@ +export * as listSearch from './listSearch'; diff --git a/packages/nodes-base/nodes/Notion/SearchFunctions.ts b/packages/nodes-base/nodes/Notion/shared/methods/listSearch.ts similarity index 93% rename from packages/nodes-base/nodes/Notion/SearchFunctions.ts rename to packages/nodes-base/nodes/Notion/shared/methods/listSearch.ts index 4501ca2360..1caba20dcf 100644 --- a/packages/nodes-base/nodes/Notion/SearchFunctions.ts +++ b/packages/nodes-base/nodes/Notion/shared/methods/listSearch.ts @@ -4,7 +4,7 @@ import type { INodeListSearchItems, INodeListSearchResult, } from 'n8n-workflow'; -import { notionApiRequestAllItems } from './GenericFunctions'; +import { notionApiRequestAllItems } from '../GenericFunctions'; export async function getDatabases( this: ILoadOptionsFunctions, diff --git a/packages/nodes-base/nodes/Notion/test/GenericFunctions.test.ts b/packages/nodes-base/nodes/Notion/test/GenericFunctions.test.ts index 288aa4e110..dc5baba799 100644 --- a/packages/nodes-base/nodes/Notion/test/GenericFunctions.test.ts +++ b/packages/nodes-base/nodes/Notion/test/GenericFunctions.test.ts @@ -1,4 +1,4 @@ -import { formatBlocks } from '../GenericFunctions'; +import { formatBlocks } from '../shared/GenericFunctions'; describe('Test NotionV2, formatBlocks', () => { it('should format to_do block', () => { diff --git a/packages/nodes-base/nodes/Notion/v1/NotionV1.node.ts b/packages/nodes-base/nodes/Notion/v1/NotionV1.node.ts index 2363f2556f..587094b91b 100644 --- a/packages/nodes-base/nodes/Notion/v1/NotionV1.node.ts +++ b/packages/nodes-base/nodes/Notion/v1/NotionV1.node.ts @@ -10,23 +10,23 @@ import type { } from 'n8n-workflow'; import moment from 'moment-timezone'; -import type { SortData } from '../GenericFunctions'; +import type { SortData } from '../shared/GenericFunctions'; import { extractDatabaseId, extractDatabaseMentionRLC, extractPageId, formatBlocks, formatTitle, - getBlockTypes, + getBlockTypesOptions, mapFilters, mapProperties, mapSorting, notionApiRequest, notionApiRequestAllItems, simplifyObjects, -} from '../GenericFunctions'; +} from '../shared/GenericFunctions'; -import { getDatabases } from '../SearchFunctions'; +import { listSearch } from '../shared/methods'; import { versionDescription } from './VersionDescription'; export class NotionV1 implements INodeType { @@ -40,9 +40,7 @@ export class NotionV1 implements INodeType { } methods = { - listSearch: { - getDatabases, - }, + listSearch, loadOptions: { async getDatabaseProperties(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; @@ -104,7 +102,7 @@ export class NotionV1 implements INodeType { return returnData; }, async getBlockTypes(this: ILoadOptionsFunctions): Promise { - return getBlockTypes(); + return getBlockTypesOptions(); }, async getPropertySelectValues(this: ILoadOptionsFunctions): Promise { const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|'); diff --git a/packages/nodes-base/nodes/Notion/v1/VersionDescription.ts b/packages/nodes-base/nodes/Notion/v1/VersionDescription.ts index af7d7c1065..6f08675439 100644 --- a/packages/nodes-base/nodes/Notion/v1/VersionDescription.ts +++ b/packages/nodes-base/nodes/Notion/v1/VersionDescription.ts @@ -1,14 +1,17 @@ /* eslint-disable n8n-nodes-base/node-filename-against-convention */ import type { INodeTypeDescription } from 'n8n-workflow'; -import { databaseFields, databaseOperations } from '../DatabaseDescription'; +import { databaseFields, databaseOperations } from '../shared/descriptions/DatabaseDescription'; -import { userFields, userOperations } from '../UserDescription'; +import { userFields, userOperations } from '../shared/descriptions/UserDescription'; -import { pageFields, pageOperations } from '../PageDescription'; +import { pageFields, pageOperations } from '../shared/descriptions/PageDescription'; -import { blockFields, blockOperations } from '../BlockDescription'; +import { blockFields, blockOperations } from '../shared/descriptions/BlockDescription'; -import { databasePageFields, databasePageOperations } from '../DatabasePageDescription'; +import { + databasePageFields, + databasePageOperations, +} from '../shared/descriptions/DatabasePageDescription'; export const versionDescription: INodeTypeDescription = { displayName: 'Notion', diff --git a/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts b/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts index 2809f8ff9e..09e67bc4ea 100644 --- a/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts +++ b/packages/nodes-base/nodes/Notion/v2/NotionV2.node.ts @@ -1,17 +1,14 @@ import type { IExecuteFunctions, IDataObject, - ILoadOptionsFunctions, INodeExecutionData, - INodePropertyOptions, INodeType, INodeTypeBaseDescription, INodeTypeDescription, } from 'n8n-workflow'; import { jsonParse, NodeApiError } from 'n8n-workflow'; -import moment from 'moment-timezone'; -import type { SortData, FileRecord } from '../GenericFunctions'; +import type { SortData, FileRecord } from '../shared/GenericFunctions'; import { downloadFiles, extractDatabaseId, @@ -19,7 +16,6 @@ import { extractPageId, formatBlocks, formatTitle, - getBlockTypes, mapFilters, mapProperties, mapSorting, @@ -29,9 +25,10 @@ import { simplifyBlocksOutput, simplifyObjects, validateJSON, -} from '../GenericFunctions'; +} from '../shared/GenericFunctions'; -import { getDatabases } from '../SearchFunctions'; +import { listSearch } from '../shared/methods'; +import { loadOptions } from './methods'; import { versionDescription } from './VersionDescription'; export class NotionV2 implements INodeType { @@ -44,290 +41,138 @@ export class NotionV2 implements INodeType { }; } - methods = { - listSearch: { - getDatabases, - }, - loadOptions: { - async getDatabaseProperties(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; - const databaseId = this.getCurrentNodeParameter('databaseId', { - extractValue: true, - }) as string; - const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); - for (const key of Object.keys(properties as IDataObject)) { - //remove parameters that cannot be set from the API. - if ( - ![ - 'created_time', - 'last_edited_time', - 'created_by', - 'last_edited_by', - 'formula', - 'rollup', - ].includes(properties[key].type as string) - ) { - returnData.push({ - name: `${key}`, - value: `${key}|${properties[key].type}`, - }); - } - } - returnData.sort((a, b) => { - if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { - return -1; - } - if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) { - return 1; - } - return 0; - }); - return returnData; - }, - async getFilterProperties(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; - const databaseId = this.getCurrentNodeParameter('databaseId', { - extractValue: true, - }) as string; - const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); - for (const key of Object.keys(properties as IDataObject)) { - returnData.push({ - name: `${key}`, - value: `${key}|${properties[key].type}`, - }); - } - returnData.sort((a, b) => { - if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { - return -1; - } - if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) { - return 1; - } - return 0; - }); - return returnData; - }, - async getBlockTypes(this: ILoadOptionsFunctions): Promise { - return getBlockTypes(); - }, - async getPropertySelectValues(this: ILoadOptionsFunctions): Promise { - const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|'); - const databaseId = this.getCurrentNodeParameter('databaseId', { - extractValue: true, - }) as string; - const resource = this.getCurrentNodeParameter('resource') as string; - const operation = this.getCurrentNodeParameter('operation') as string; - const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); - if (resource === 'databasePage') { - if (['multi_select', 'select', 'status'].includes(type) && operation === 'getAll') { - return properties[name][type].options.map((option: IDataObject) => ({ - name: option.name, - value: option.name, - })); - } else if ( - ['multi_select', 'select', 'status'].includes(type) && - ['create', 'update'].includes(operation) - ) { - return properties[name][type].options.map((option: IDataObject) => ({ - name: option.name, - value: option.name, - })); - } - } - return properties[name][type].options.map((option: IDataObject) => ({ - name: option.name, - value: option.id, - })); - }, - async getUsers(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; - const users = await notionApiRequestAllItems.call(this, 'results', 'GET', '/users'); - for (const user of users) { - if (user.type === 'person') { - returnData.push({ - name: user.name, - value: user.id, - }); - } - } - return returnData; - }, - async getDatabaseIdFromPage(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; - const pageId = extractPageId( - this.getCurrentNodeParameter('pageId', { extractValue: true }) as string, - ); - const { - parent: { database_id: databaseId }, - } = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`); - const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); - for (const key of Object.keys(properties as IDataObject)) { - //remove parameters that cannot be set from the API. - if ( - ![ - 'created_time', - 'last_edited_time', - 'created_by', - 'last_edited_by', - 'formula', - 'rollup', - ].includes(properties[key].type as string) - ) { - returnData.push({ - name: `${key}`, - value: `${key}|${properties[key].type}`, - }); - } - } - returnData.sort((a, b) => { - if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { - return -1; - } - if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) { - return 1; - } - return 0; - }); - return returnData; - }, - - async getDatabaseOptionsFromPage( - this: ILoadOptionsFunctions, - ): Promise { - const pageId = extractPageId( - this.getCurrentNodeParameter('pageId', { extractValue: true }) as string, - ); - const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|'); - const { - parent: { database_id: databaseId }, - } = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`); - const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); - return properties[name][type].options.map((option: IDataObject) => ({ - name: option.name, - value: option.name, - })); - }, - - // Get all the timezones to display them to user so that they can - // select them easily - async getTimezones(this: ILoadOptionsFunctions): Promise { - const returnData: INodePropertyOptions[] = []; - for (const timezone of moment.tz.names()) { - const timezoneName = timezone; - const timezoneId = timezone; - returnData.push({ - name: timezoneName, - value: timezoneId, - }); - } - returnData.unshift({ - name: 'Default', - value: 'default', - description: 'Timezone set in n8n', - }); - return returnData; - }, - }, - }; + methods = { listSearch, loadOptions }; async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); - const returnData: INodeExecutionData[] = []; - const length = items.length; - let responseData; - const qs: IDataObject = {}; - const timezone = this.getTimezone(); - const resource = this.getNodeParameter('resource', 0); const operation = this.getNodeParameter('operation', 0); + + const itemsLength = items.length; + const timezone = this.getTimezone(); + const qs: IDataObject = {}; + + let returnData: INodeExecutionData[] = []; + let responseData; let download = false; if (resource === 'block') { if (operation === 'append') { - for (let i = 0; i < length; i++) { - const blockId = extractPageId( - this.getNodeParameter('blockId', i, '', { extractValue: true }) as string, - ); - const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[]; - extractDatabaseMentionRLC(blockValues); - const body: IDataObject = { - children: formatBlocks(blockValues), - }; - const block = await notionApiRequest.call( - this, - 'PATCH', - `/blocks/${blockId}/children`, - body, - ); + for (let i = 0; i < itemsLength; i++) { + try { + const blockId = extractPageId( + this.getNodeParameter('blockId', i, '', { extractValue: true }) as string, + ); + const blockValues = this.getNodeParameter( + 'blockUi.blockValues', + i, + [], + ) as IDataObject[]; + extractDatabaseMentionRLC(blockValues); + const body: IDataObject = { + children: formatBlocks(blockValues), + }; + const block = await notionApiRequest.call( + this, + 'PATCH', + `/blocks/${blockId}/children`, + body, + ); - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(block as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(block as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; + } + } } } if (operation === 'getAll') { - for (let i = 0; i < length; i++) { - const blockId = extractPageId( - this.getNodeParameter('blockId', i, '', { extractValue: true }) as string, - ); - const returnAll = this.getNodeParameter('returnAll', i); - const fetchNestedBlocks = this.getNodeParameter('fetchNestedBlocks', i) as boolean; - - if (returnAll) { - responseData = await notionApiRequestAllItems.call( - this, - 'results', - 'GET', - `/blocks/${blockId}/children`, - {}, + for (let i = 0; i < itemsLength; i++) { + try { + const blockId = extractPageId( + this.getNodeParameter('blockId', i, '', { extractValue: true }) as string, ); + const returnAll = this.getNodeParameter('returnAll', i); + const fetchNestedBlocks = this.getNodeParameter('fetchNestedBlocks', i) as boolean; - if (fetchNestedBlocks) { - responseData = await notionApiRequestGetBlockChildrens.call(this, responseData); - } - } else { - const limit = this.getNodeParameter('limit', i); - qs.page_size = limit; - responseData = await notionApiRequest.call( - this, - 'GET', - `/blocks/${blockId}/children`, - {}, - qs, - ); - const results = responseData.results; + if (returnAll) { + responseData = await notionApiRequestAllItems.call( + this, + 'results', + 'GET', + `/blocks/${blockId}/children`, + {}, + ); - if (fetchNestedBlocks) { - responseData = await notionApiRequestGetBlockChildrens.call(this, results, [], limit); + if (fetchNestedBlocks) { + responseData = await notionApiRequestGetBlockChildrens.call(this, responseData); + } } else { - responseData = results; + const limit = this.getNodeParameter('limit', i); + qs.page_size = limit; + responseData = await notionApiRequest.call( + this, + 'GET', + `/blocks/${blockId}/children`, + {}, + qs, + ); + const results = responseData.results; + + if (fetchNestedBlocks) { + responseData = await notionApiRequestGetBlockChildrens.call( + this, + results, + [], + limit, + ); + } else { + responseData = results; + } + } + + responseData = responseData.map((_data: IDataObject) => ({ + object: _data.object, + parent_id: blockId, + ..._data, + })); + + const nodeVersion = this.getNode().typeVersion; + + if (nodeVersion > 2) { + const simplifyOutput = this.getNodeParameter('simplifyOutput', i) as boolean; + + if (simplifyOutput) { + responseData = simplifyBlocksOutput(responseData, blockId); + } + } + + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; } } - - responseData = responseData.map((_data: IDataObject) => ({ - object: _data.object, - parent_id: blockId, - ..._data, - })); - - const nodeVersion = this.getNode().typeVersion; - - if (nodeVersion > 2) { - const simplifyOutput = this.getNodeParameter('simplifyOutput', i) as boolean; - - if (simplifyOutput) { - responseData = simplifyBlocksOutput(responseData, blockId); - } - } - - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); } } } @@ -335,104 +180,137 @@ export class NotionV2 implements INodeType { if (resource === 'database') { if (operation === 'get') { const simple = this.getNodeParameter('simple', 0) as boolean; - for (let i = 0; i < length; i++) { - const databaseId = extractDatabaseId( - this.getNodeParameter('databaseId', i, '', { extractValue: true }) as string, - ); - responseData = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); - if (simple) { - responseData = simplifyObjects(responseData, download)[0]; - } + for (let i = 0; i < itemsLength; i++) { + try { + const databaseId = extractDatabaseId( + this.getNodeParameter('databaseId', i, '', { extractValue: true }) as string, + ); + responseData = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); + if (simple) { + responseData = simplifyObjects(responseData, download)[0]; + } - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; + } + } } } if (operation === 'getAll') { const simple = this.getNodeParameter('simple', 0) as boolean; - for (let i = 0; i < length; i++) { - const body: IDataObject = { - filter: { property: 'object', value: 'database' }, - }; - const returnAll = this.getNodeParameter('returnAll', i); - if (returnAll) { - responseData = await notionApiRequestAllItems.call( - this, - 'results', - 'POST', - '/search', - body, - ); - } else { - body.page_size = this.getNodeParameter('limit', i); - responseData = await notionApiRequest.call(this, 'POST', '/search', body); - responseData = responseData.results; - } - if (simple) { - responseData = simplifyObjects(responseData, download); - } + for (let i = 0; i < itemsLength; i++) { + try { + const body: IDataObject = { + filter: { property: 'object', value: 'database' }, + }; + const returnAll = this.getNodeParameter('returnAll', i); + if (returnAll) { + responseData = await notionApiRequestAllItems.call( + this, + 'results', + 'POST', + '/search', + body, + ); + } else { + body.page_size = this.getNodeParameter('limit', i); + responseData = await notionApiRequest.call(this, 'POST', '/search', body); + responseData = responseData.results; + } + if (simple) { + responseData = simplifyObjects(responseData, download); + } - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; + } + } } } if (operation === 'search') { - for (let i = 0; i < length; i++) { - const text = this.getNodeParameter('text', i) as string; - const options = this.getNodeParameter('options', i); - const returnAll = this.getNodeParameter('returnAll', i); - const simple = this.getNodeParameter('simple', i) as boolean; - const body: IDataObject = { - filter: { - property: 'object', - value: 'database', - }, - }; + for (let i = 0; i < itemsLength; i++) { + try { + const text = this.getNodeParameter('text', i) as string; + const options = this.getNodeParameter('options', i); + const returnAll = this.getNodeParameter('returnAll', i); + const simple = this.getNodeParameter('simple', i) as boolean; + const body: IDataObject = { + filter: { + property: 'object', + value: 'database', + }, + }; - if (text) { - body.query = text; - } - if (options.sort) { - const sort = ((options.sort as IDataObject)?.sortValue as IDataObject) || {}; - body.sort = sort; - } - if (returnAll) { - responseData = await notionApiRequestAllItems.call( - this, - 'results', - 'POST', - '/search', - body, + if (text) { + body.query = text; + } + if (options.sort) { + const sort = ((options.sort as IDataObject)?.sortValue as IDataObject) || {}; + body.sort = sort; + } + if (returnAll) { + responseData = await notionApiRequestAllItems.call( + this, + 'results', + 'POST', + '/search', + body, + ); + } else { + qs.limit = this.getNodeParameter('limit', i); + responseData = await notionApiRequestAllItems.call( + this, + 'results', + 'POST', + '/search', + body, + ); + responseData = responseData.splice(0, qs.limit); + } + + if (simple) { + responseData = simplifyObjects(responseData, download); + } + + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, ); - } else { - qs.limit = this.getNodeParameter('limit', i); - responseData = await notionApiRequestAllItems.call( - this, - 'results', - 'POST', - '/search', - body, - ); - responseData = responseData.splice(0, qs.limit); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; + } } - - if (simple) { - responseData = simplifyObjects(responseData, download); - } - - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); } } } @@ -449,346 +327,453 @@ export class NotionV2 implements INodeType { titleKey = key; } } - for (let i = 0; i < length; i++) { - const title = this.getNodeParameter('title', i) as string; - const simple = this.getNodeParameter('simple', i) as boolean; + for (let i = 0; i < itemsLength; i++) { + try { + const title = this.getNodeParameter('title', i) as string; + const simple = this.getNodeParameter('simple', i) as boolean; - const body: { [key: string]: any } = { - parent: {}, - properties: {}, - }; - if (title !== '') { - body.properties[titleKey] = { - title: [ - { - text: { - content: title, - }, - }, - ], + const body: { [key: string]: any } = { + parent: {}, + properties: {}, }; - } - body.parent.database_id = this.getNodeParameter('databaseId', i, '', { - extractValue: true, - }) as string; - const propertiesValues = this.getNodeParameter( - 'propertiesUi.propertyValues', - i, - [], - ) as IDataObject[]; - if (propertiesValues.length !== 0) { - body.properties = Object.assign( - body.properties, - mapProperties.call(this, propertiesValues, timezone, 2) as IDataObject, - ); - } - const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[]; - extractDatabaseMentionRLC(blockValues); - body.children = formatBlocks(blockValues); + if (title !== '') { + body.properties[titleKey] = { + title: [ + { + text: { + content: title, + }, + }, + ], + }; + } + body.parent.database_id = this.getNodeParameter('databaseId', i, '', { + extractValue: true, + }) as string; + const propertiesValues = this.getNodeParameter( + 'propertiesUi.propertyValues', + i, + [], + ) as IDataObject[]; + if (propertiesValues.length !== 0) { + body.properties = Object.assign( + body.properties, + mapProperties.call(this, propertiesValues, timezone, 2) as IDataObject, + ); + } + const blockValues = this.getNodeParameter( + 'blockUi.blockValues', + i, + [], + ) as IDataObject[]; + extractDatabaseMentionRLC(blockValues); + body.children = formatBlocks(blockValues); - const options = this.getNodeParameter('options', i); - if (options.icon) { - if (options.iconType && options.iconType === 'file') { - body.icon = { external: { url: options.icon } }; + const options = this.getNodeParameter('options', i); + if (options.icon) { + if (options.iconType && options.iconType === 'file') { + body.icon = { external: { url: options.icon } }; + } else { + body.icon = { emoji: options.icon }; + } + } + + responseData = await notionApiRequest.call(this, 'POST', '/pages', body); + if (simple) { + responseData = simplifyObjects(responseData); + } + + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); } else { - body.icon = { emoji: options.icon }; + throw error; } } - - responseData = await notionApiRequest.call(this, 'POST', '/pages', body); - if (simple) { - responseData = simplifyObjects(responseData); - } - - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); } } if (operation === 'get') { - for (let i = 0; i < length; i++) { - const pageId = extractPageId( - this.getNodeParameter('pageId', i, '', { extractValue: true }) as string, - ); - const simple = this.getNodeParameter('simple', i) as boolean; - responseData = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`); - if (simple) { - responseData = simplifyObjects(responseData, download); - } + for (let i = 0; i < itemsLength; i++) { + try { + const pageId = extractPageId( + this.getNodeParameter('pageId', i, '', { extractValue: true }) as string, + ); + const simple = this.getNodeParameter('simple', i) as boolean; + responseData = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`); + if (simple) { + responseData = simplifyObjects(responseData, download); + } - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; + } + } } } if (operation === 'getAll') { - for (let i = 0; i < length; i++) { - download = this.getNodeParameter('options.downloadFiles', 0, false) as boolean; - const simple = this.getNodeParameter('simple', 0) as boolean; - const databaseId = this.getNodeParameter('databaseId', i, '', { - extractValue: true, - }) as string; - const returnAll = this.getNodeParameter('returnAll', i); - const filterType = this.getNodeParameter('filterType', 0) as string; - const conditions = this.getNodeParameter('filters.conditions', i, []) as IDataObject[]; - const sort = this.getNodeParameter('options.sort.sortValue', i, []) as IDataObject[]; - const body: IDataObject = { - filter: {}, - }; + for (let i = 0; i < itemsLength; i++) { + try { + download = this.getNodeParameter('options.downloadFiles', 0, false) as boolean; + const simple = this.getNodeParameter('simple', 0) as boolean; + const databaseId = this.getNodeParameter('databaseId', i, '', { + extractValue: true, + }) as string; + const returnAll = this.getNodeParameter('returnAll', i); + const filterType = this.getNodeParameter('filterType', 0) as string; + const conditions = this.getNodeParameter('filters.conditions', i, []) as IDataObject[]; + const sort = this.getNodeParameter('options.sort.sortValue', i, []) as IDataObject[]; + const body: IDataObject = { + filter: {}, + }; - if (filterType === 'manual') { - const matchType = this.getNodeParameter('matchType', 0) as string; - if (matchType === 'anyFilter') { - Object.assign(body.filter!, { - or: conditions.map((data) => mapFilters([data], timezone)), - }); - } else if (matchType === 'allFilters') { - Object.assign(body.filter!, { - and: conditions.map((data) => mapFilters([data], timezone)), - }); + if (filterType === 'manual') { + const matchType = this.getNodeParameter('matchType', 0) as string; + if (matchType === 'anyFilter') { + Object.assign(body.filter!, { + or: conditions.map((data) => mapFilters([data], timezone)), + }); + } else if (matchType === 'allFilters') { + Object.assign(body.filter!, { + and: conditions.map((data) => mapFilters([data], timezone)), + }); + } + } else if (filterType === 'json') { + const filterJson = this.getNodeParameter('filterJson', i) as string; + if (validateJSON(filterJson) !== undefined) { + body.filter = jsonParse(filterJson); + } else { + throw new NodeApiError(this.getNode(), { + message: 'Filters (JSON) must be a valid json', + }); + } } - } else if (filterType === 'json') { - const filterJson = this.getNodeParameter('filterJson', i) as string; - if (validateJSON(filterJson) !== undefined) { - body.filter = jsonParse(filterJson); + + if (!Object.keys(body.filter as IDataObject).length) { + delete body.filter; + } + if (sort) { + body.sorts = mapSorting(sort as SortData[]); + } + if (returnAll) { + responseData = await notionApiRequestAllItems.call( + this, + 'results', + 'POST', + `/databases/${databaseId}/query`, + body, + {}, + ); } else { - throw new NodeApiError(this.getNode(), { - message: 'Filters (JSON) must be a valid json', + body.page_size = this.getNodeParameter('limit', i); + responseData = await notionApiRequest.call( + this, + 'POST', + `/databases/${databaseId}/query`, + body, + qs, + ); + responseData = responseData.results; + } + if (download) { + responseData = await downloadFiles.call(this, responseData as FileRecord[], [ + { item: i }, + ]); + } + if (simple) { + responseData = simplifyObjects(responseData, download); + } + + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, }); + } else { + throw error; } } - - if (!Object.keys(body.filter as IDataObject).length) { - delete body.filter; - } - if (sort) { - body.sorts = mapSorting(sort as SortData[]); - } - if (returnAll) { - responseData = await notionApiRequestAllItems.call( - this, - 'results', - 'POST', - `/databases/${databaseId}/query`, - body, - {}, - ); - } else { - body.page_size = this.getNodeParameter('limit', i); - responseData = await notionApiRequest.call( - this, - 'POST', - `/databases/${databaseId}/query`, - body, - qs, - ); - responseData = responseData.results; - } - if (download) { - responseData = await downloadFiles.call(this, responseData as FileRecord[], [ - { item: i }, - ]); - } - if (simple) { - responseData = simplifyObjects(responseData, download); - } - - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); } } if (operation === 'update') { - for (let i = 0; i < length; i++) { - const pageId = extractPageId( - this.getNodeParameter('pageId', i, '', { extractValue: true }) as string, - ); - const simple = this.getNodeParameter('simple', i) as boolean; - const properties = this.getNodeParameter( - 'propertiesUi.propertyValues', - i, - [], - ) as IDataObject[]; + for (let i = 0; i < itemsLength; i++) { + try { + const pageId = extractPageId( + this.getNodeParameter('pageId', i, '', { extractValue: true }) as string, + ); + const simple = this.getNodeParameter('simple', i) as boolean; + const properties = this.getNodeParameter( + 'propertiesUi.propertyValues', + i, + [], + ) as IDataObject[]; - const body: { [key: string]: any } = { - properties: {}, - }; - if (properties.length !== 0) { - body.properties = mapProperties.call(this, properties, timezone, 2) as IDataObject; - } + const body: { [key: string]: any } = { + properties: {}, + }; + if (properties.length !== 0) { + body.properties = mapProperties.call(this, properties, timezone, 2) as IDataObject; + } - const options = this.getNodeParameter('options', i); - if (options.icon) { - if (options.iconType && options.iconType === 'file') { - body.icon = { type: 'external', external: { url: options.icon } }; + const options = this.getNodeParameter('options', i); + if (options.icon) { + if (options.iconType && options.iconType === 'file') { + body.icon = { type: 'external', external: { url: options.icon } }; + } else { + body.icon = { type: 'emoji', emoji: options.icon }; + } + } + + responseData = await notionApiRequest.call(this, 'PATCH', `/pages/${pageId}`, body); + if (simple) { + responseData = simplifyObjects(responseData, false); + } + + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); } else { - body.icon = { type: 'emoji', emoji: options.icon }; + throw error; } } - - responseData = await notionApiRequest.call(this, 'PATCH', `/pages/${pageId}`, body); - if (simple) { - responseData = simplifyObjects(responseData, false); - } - - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); } } } if (resource === 'user') { if (operation === 'get') { - for (let i = 0; i < length; i++) { - const userId = this.getNodeParameter('userId', i) as string; - responseData = await notionApiRequest.call(this, 'GET', `/users/${userId}`); + for (let i = 0; i < itemsLength; i++) { + try { + const userId = this.getNodeParameter('userId', i) as string; + responseData = await notionApiRequest.call(this, 'GET', `/users/${userId}`); - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; + } + } } } if (operation === 'getAll') { - for (let i = 0; i < length; i++) { - const returnAll = this.getNodeParameter('returnAll', i); - if (returnAll) { - responseData = await notionApiRequestAllItems.call(this, 'results', 'GET', '/users'); - } else { - qs.limit = this.getNodeParameter('limit', i); - responseData = await notionApiRequestAllItems.call(this, 'results', 'GET', '/users'); - responseData = responseData.splice(0, qs.limit); - } + for (let i = 0; i < itemsLength; i++) { + try { + const returnAll = this.getNodeParameter('returnAll', i); + if (returnAll) { + responseData = await notionApiRequestAllItems.call(this, 'results', 'GET', '/users'); + } else { + qs.limit = this.getNodeParameter('limit', i); + responseData = await notionApiRequestAllItems.call(this, 'results', 'GET', '/users'); + responseData = responseData.splice(0, qs.limit); + } - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; + } + } } } } if (resource === 'page') { if (operation === 'archive') { - for (let i = 0; i < length; i++) { - const pageId = extractPageId( - this.getNodeParameter('pageId', i, '', { extractValue: true }) as string, - ); - const simple = this.getNodeParameter('simple', i) as boolean; - responseData = await notionApiRequest.call(this, 'PATCH', `/pages/${pageId}`, { - archived: true, - }); - if (simple) { - responseData = simplifyObjects(responseData, download); - } + for (let i = 0; i < itemsLength; i++) { + try { + const pageId = extractPageId( + this.getNodeParameter('pageId', i, '', { extractValue: true }) as string, + ); + const simple = this.getNodeParameter('simple', i) as boolean; + responseData = await notionApiRequest.call(this, 'PATCH', `/pages/${pageId}`, { + archived: true, + }); + if (simple) { + responseData = simplifyObjects(responseData, download); + } - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; + } + } } } if (operation === 'create') { - for (let i = 0; i < length; i++) { - const simple = this.getNodeParameter('simple', i) as boolean; - const body: { [key: string]: any } = { - parent: {}, - properties: {}, - }; - body.parent.page_id = extractPageId( - this.getNodeParameter('pageId', i, '', { extractValue: true }) as string, - ); - body.properties = formatTitle(this.getNodeParameter('title', i) as string); - const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[]; - extractDatabaseMentionRLC(blockValues); - body.children = formatBlocks(blockValues); + for (let i = 0; i < itemsLength; i++) { + try { + const simple = this.getNodeParameter('simple', i) as boolean; + const body: { [key: string]: any } = { + parent: {}, + properties: {}, + }; + body.parent.page_id = extractPageId( + this.getNodeParameter('pageId', i, '', { extractValue: true }) as string, + ); + body.properties = formatTitle(this.getNodeParameter('title', i) as string); + const blockValues = this.getNodeParameter( + 'blockUi.blockValues', + i, + [], + ) as IDataObject[]; + extractDatabaseMentionRLC(blockValues); + body.children = formatBlocks(blockValues); - const options = this.getNodeParameter('options', i); - if (options.icon) { - if (options.iconType && options.iconType === 'file') { - body.icon = { external: { url: options.icon } }; + const options = this.getNodeParameter('options', i); + if (options.icon) { + if (options.iconType && options.iconType === 'file') { + body.icon = { external: { url: options.icon } }; + } else { + body.icon = { emoji: options.icon }; + } + } + + responseData = await notionApiRequest.call(this, 'POST', '/pages', body); + if (simple) { + responseData = simplifyObjects(responseData, download); + } + + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, + ); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); } else { - body.icon = { emoji: options.icon }; + throw error; } } - - responseData = await notionApiRequest.call(this, 'POST', '/pages', body); - if (simple) { - responseData = simplifyObjects(responseData, download); - } - - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); } } if (operation === 'search') { - for (let i = 0; i < length; i++) { - const text = this.getNodeParameter('text', i) as string; - const options = this.getNodeParameter('options', i); - const returnAll = this.getNodeParameter('returnAll', i); - const simple = this.getNodeParameter('simple', i) as boolean; - const body: IDataObject = {}; + for (let i = 0; i < itemsLength; i++) { + try { + const text = this.getNodeParameter('text', i) as string; + const options = this.getNodeParameter('options', i); + const returnAll = this.getNodeParameter('returnAll', i); + const simple = this.getNodeParameter('simple', i) as boolean; + const body: IDataObject = {}; - if (text) { - body.query = text; - } - if (options.filter) { - const filter = ((options.filter as IDataObject)?.filters as IDataObject[]) || []; - body.filter = filter; - } - if (options.sort) { - const sort = ((options.sort as IDataObject)?.sortValue as IDataObject) || {}; - body.sort = sort; - } - if (returnAll) { - responseData = await notionApiRequestAllItems.call( - this, - 'results', - 'POST', - '/search', - body, + if (text) { + body.query = text; + } + if (options.filter) { + const filter = ((options.filter as IDataObject)?.filters as IDataObject[]) || []; + body.filter = filter; + } + if (options.sort) { + const sort = ((options.sort as IDataObject)?.sortValue as IDataObject) || {}; + body.sort = sort; + } + if (returnAll) { + responseData = await notionApiRequestAllItems.call( + this, + 'results', + 'POST', + '/search', + body, + ); + } else { + qs.limit = this.getNodeParameter('limit', i); + responseData = await notionApiRequestAllItems.call( + this, + 'results', + 'POST', + '/search', + body, + ); + responseData = responseData.splice(0, qs.limit); + } + + if (simple) { + responseData = simplifyObjects(responseData, download); + } + + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData as IDataObject), + { itemData: { item: i } }, ); - } else { - qs.limit = this.getNodeParameter('limit', i); - responseData = await notionApiRequestAllItems.call( - this, - 'results', - 'POST', - '/search', - body, - ); - responseData = responseData.splice(0, qs.limit); + returnData = returnData.concat(executionData); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ + json: { error: error.message }, + pairedItem: { item: i }, + }); + } else { + throw error; + } } - - if (simple) { - responseData = simplifyObjects(responseData, download); - } - - const executionData = this.helpers.constructExecutionMetaData( - this.helpers.returnJsonArray(responseData as IDataObject), - { itemData: { item: i } }, - ); - returnData.push(...executionData); } } } diff --git a/packages/nodes-base/nodes/Notion/v2/VersionDescription.ts b/packages/nodes-base/nodes/Notion/v2/VersionDescription.ts index 4917fa9f34..6e5c42c72b 100644 --- a/packages/nodes-base/nodes/Notion/v2/VersionDescription.ts +++ b/packages/nodes-base/nodes/Notion/v2/VersionDescription.ts @@ -1,14 +1,17 @@ /* eslint-disable n8n-nodes-base/node-filename-against-convention */ import type { INodeTypeDescription } from 'n8n-workflow'; -import { databaseFields, databaseOperations } from '../DatabaseDescription'; +import { databaseFields, databaseOperations } from '../shared/descriptions/DatabaseDescription'; -import { userFields, userOperations } from '../UserDescription'; +import { userFields, userOperations } from '../shared/descriptions/UserDescription'; -import { pageFields, pageOperations } from '../PageDescription'; +import { pageFields, pageOperations } from '../shared/descriptions/PageDescription'; -import { blockFields, blockOperations } from '../BlockDescription'; +import { blockFields, blockOperations } from '../shared/descriptions/BlockDescription'; -import { databasePageFields, databasePageOperations } from '../DatabasePageDescription'; +import { + databasePageFields, + databasePageOperations, +} from '../shared/descriptions/DatabasePageDescription'; export const versionDescription: INodeTypeDescription = { displayName: 'Notion', diff --git a/packages/nodes-base/nodes/Notion/v2/methods/index.ts b/packages/nodes-base/nodes/Notion/v2/methods/index.ts new file mode 100644 index 0000000000..65ff6192a3 --- /dev/null +++ b/packages/nodes-base/nodes/Notion/v2/methods/index.ts @@ -0,0 +1 @@ +export * as loadOptions from './loadOptions'; diff --git a/packages/nodes-base/nodes/Notion/v2/methods/loadOptions.ts b/packages/nodes-base/nodes/Notion/v2/methods/loadOptions.ts new file mode 100644 index 0000000000..1e0de23836 --- /dev/null +++ b/packages/nodes-base/nodes/Notion/v2/methods/loadOptions.ts @@ -0,0 +1,202 @@ +import type { IDataObject, ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow'; + +import moment from 'moment-timezone'; + +import { + extractPageId, + getBlockTypesOptions, + notionApiRequest, + notionApiRequestAllItems, +} from '../../shared/GenericFunctions'; + +export async function getDatabaseProperties( + this: ILoadOptionsFunctions, +): Promise { + const returnData: INodePropertyOptions[] = []; + const databaseId = this.getCurrentNodeParameter('databaseId', { + extractValue: true, + }) as string; + const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); + for (const key of Object.keys(properties as IDataObject)) { + //remove parameters that cannot be set from the API. + if ( + ![ + 'created_time', + 'last_edited_time', + 'created_by', + 'last_edited_by', + 'formula', + 'rollup', + ].includes(properties[key].type as string) + ) { + returnData.push({ + name: `${key}`, + value: `${key}|${properties[key].type}`, + }); + } + } + returnData.sort((a, b) => { + if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { + return -1; + } + if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) { + return 1; + } + return 0; + }); + return returnData; +} + +export async function getFilterProperties( + this: ILoadOptionsFunctions, +): Promise { + const returnData: INodePropertyOptions[] = []; + const databaseId = this.getCurrentNodeParameter('databaseId', { + extractValue: true, + }) as string; + const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); + for (const key of Object.keys(properties as IDataObject)) { + returnData.push({ + name: `${key}`, + value: `${key}|${properties[key].type}`, + }); + } + returnData.sort((a, b) => { + if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { + return -1; + } + if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) { + return 1; + } + return 0; + }); + return returnData; +} + +export async function getBlockTypes(this: ILoadOptionsFunctions): Promise { + return getBlockTypesOptions(); +} + +export async function getPropertySelectValues( + this: ILoadOptionsFunctions, +): Promise { + const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|'); + const databaseId = this.getCurrentNodeParameter('databaseId', { + extractValue: true, + }) as string; + const resource = this.getCurrentNodeParameter('resource') as string; + const operation = this.getCurrentNodeParameter('operation') as string; + const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); + if (resource === 'databasePage') { + if (['multi_select', 'select', 'status'].includes(type) && operation === 'getAll') { + return properties[name][type].options.map((option: IDataObject) => ({ + name: option.name, + value: option.name, + })); + } else if ( + ['multi_select', 'select', 'status'].includes(type) && + ['create', 'update'].includes(operation) + ) { + return properties[name][type].options.map((option: IDataObject) => ({ + name: option.name, + value: option.name, + })); + } + } + return properties[name][type].options.map((option: IDataObject) => ({ + name: option.name, + value: option.id, + })); +} + +export async function getUsers(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const users = await notionApiRequestAllItems.call(this, 'results', 'GET', '/users'); + for (const user of users) { + if (user.type === 'person') { + returnData.push({ + name: user.name, + value: user.id, + }); + } + } + return returnData; +} + +export async function getDatabaseIdFromPage( + this: ILoadOptionsFunctions, +): Promise { + const returnData: INodePropertyOptions[] = []; + const pageId = extractPageId( + this.getCurrentNodeParameter('pageId', { extractValue: true }) as string, + ); + const { + parent: { database_id: databaseId }, + } = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`); + const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); + for (const key of Object.keys(properties as IDataObject)) { + //remove parameters that cannot be set from the API. + if ( + ![ + 'created_time', + 'last_edited_time', + 'created_by', + 'last_edited_by', + 'formula', + 'rollup', + ].includes(properties[key].type as string) + ) { + returnData.push({ + name: `${key}`, + value: `${key}|${properties[key].type}`, + }); + } + } + returnData.sort((a, b) => { + if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { + return -1; + } + if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) { + return 1; + } + return 0; + }); + return returnData; +} + +export async function getDatabaseOptionsFromPage( + this: ILoadOptionsFunctions, +): Promise { + const pageId = extractPageId( + this.getCurrentNodeParameter('pageId', { extractValue: true }) as string, + ); + const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|'); + const { + parent: { database_id: databaseId }, + } = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`); + const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); + return properties[name][type].options.map((option: IDataObject) => ({ + name: option.name, + value: option.name, + })); +} + +// Get all the timezones to display them to user so that they can +// select them easily +export async function getTimezones(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + for (const timezone of moment.tz.names()) { + const timezoneName = timezone; + const timezoneId = timezone; + returnData.push({ + name: timezoneName, + value: timezoneId, + }); + } + returnData.unshift({ + name: 'Default', + value: 'default', + description: 'Timezone set in n8n', + }); + return returnData; +}