From 491611b05f752dc966a55d83d04fa559cd9942ea Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Wed, 3 Apr 2024 22:25:19 +0800 Subject: [PATCH] sync items and highlights to user created database in notion --- .../api/src/resolvers/integrations/index.ts | 19 +- .../api/src/services/integrations/notion.ts | 171 +++++++++--------- 2 files changed, 100 insertions(+), 90 deletions(-) diff --git a/packages/api/src/resolvers/integrations/index.ts b/packages/api/src/resolvers/integrations/index.ts index fec1a9a82..b1fc0c03a 100644 --- a/packages/api/src/resolvers/integrations/index.ts +++ b/packages/api/src/resolvers/integrations/index.ts @@ -40,6 +40,7 @@ import { saveIntegration, updateIntegration, } from '../../services/integrations' +import { NotionClient } from '../../services/integrations/notion' import { analytics } from '../../utils/analytics' import { deleteTask, @@ -57,15 +58,14 @@ export const setIntegrationResolver = authorized< ...input, user: { id: uid }, id: input.id || undefined, - type: input.type || IntegrationType.Export, + type: input.type || undefined, syncedAt: input.syncedAt ? new Date(input.syncedAt) : undefined, importItemState: input.type === IntegrationType.Import ? input.importItemState || ImportItemState.Unarchived // default to unarchived : undefined, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - settings: input.settings, } + if (input.id) { // Update const existingIntegration = await findIntegration({ id: input.id }, uid) @@ -96,6 +96,19 @@ export const setIntegrationResolver = authorized< if (integration.name.toLowerCase() === 'readwise') { // create a task to export all the items for readwise temporarily await enqueueExportToIntegration(integration.id, uid) + } else if (integration.name.toLowerCase() === 'notion') { + const settings = integration.settings as { parentDatabaseId?: string } + if (settings.parentDatabaseId) { + // update notion database properties + const notion = new NotionClient(integration.token, integration) + try { + await notion.updateDatabase(settings.parentDatabaseId) + } catch (error) { + return { + errorCodes: [SetIntegrationErrorCode.BadRequest], + } + } + } } analytics.capture({ diff --git a/packages/api/src/services/integrations/notion.ts b/packages/api/src/services/integrations/notion.ts index 7e891287d..31ffc2cff 100644 --- a/packages/api/src/services/integrations/notion.ts +++ b/packages/api/src/services/integrations/notion.ts @@ -1,6 +1,5 @@ import { Client } from '@notionhq/client' import axios from 'axios' -import { updateIntegration } from '.' import { Integration } from '../../entity/integration' import { LibraryItem } from '../../entity/library_item' import { env } from '../../env' @@ -111,7 +110,7 @@ type Property = 'highlights' interface Settings { parentPageId: string parentDatabaseId: string - properties: Property[] + properties?: Property[] } export class NotionClient implements IntegrationClient { @@ -244,7 +243,7 @@ export class NotionClient implements IntegrationClient { : undefined, }, children: - settings.properties.includes('highlights') && item.highlights + settings.properties?.includes('highlights') && item.highlights ? item.highlights .filter( (highlight) => !lastSync || highlight.updatedAt > lastSync // only new highlights @@ -315,103 +314,101 @@ export class NotionClient implements IntegrationClient { return false } - const pageId = settings.parentPageId - if (!pageId) { - logger.error('Notion parent page id not found') - return false - } - - let databaseId = settings.parentDatabaseId + const databaseId = settings.parentDatabaseId if (!databaseId) { - // create a database for the items - const database = await this.client.databases.create({ - parent: { - page_id: pageId, - }, - title: [ - { - text: { - content: 'Library', - }, - }, - ], - description: [ - { - text: { - content: 'Library of saved items from Omnivore', - }, - }, - ], - properties: { - Title: { - title: {}, - }, - Author: { - rich_text: {}, - }, - 'Original URL': { - url: {}, - }, - 'Omnivore URL': { - url: {}, - }, - 'Saved At': { - date: {}, - }, - 'Last Updated': { - date: {}, - }, - Tags: { - multi_select: {}, - }, - }, - }) - - // save the database id - databaseId = database.id - settings.parentDatabaseId = databaseId - await updateIntegration( - this.integrationData.id, - { - settings, - }, - this.integrationData.user.id - ) + logger.error('Notion database id not found') + return false } await Promise.all( items.map(async (item) => { - const notionPage = this.itemToNotionPage( - item, - settings, - this.integrationData?.syncedAt - ) - const url = notionPage.properties['Omnivore URL'].url + try { + const notionPage = this.itemToNotionPage( + item, + settings, + this.integrationData?.syncedAt + ) + const url = notionPage.properties['Omnivore URL'].url - const existingPage = await this.findPage(url, databaseId) - if (existingPage) { - // update the page - await this.client.pages.update({ - page_id: existingPage.id, - properties: notionPage.properties, - }) - - // append the children incrementally - if (notionPage.children && notionPage.children.length > 0) { - await this.client.blocks.children.append({ - block_id: existingPage.id, - children: notionPage.children, + const existingPage = await this.findPage(url, databaseId) + if (existingPage) { + // update the page + await this.client.pages.update({ + page_id: existingPage.id, + properties: notionPage.properties, }) + + // append the children incrementally + if (notionPage.children && notionPage.children.length > 0) { + await this.client.blocks.children.append({ + block_id: existingPage.id, + children: notionPage.children, + }) + } + + return } - return + // create the page + return this.createPage(notionPage) + } catch (error) { + logger.error(error) + return false } - - // create the page - return this.createPage(notionPage) }) ) return true } + + private findDatabase = async (databaseId: string) => { + return this.client.databases.retrieve({ + database_id: databaseId, + }) + } + + updateDatabase = async (databaseId: string) => { + const database = await this.findDatabase(databaseId) + + await this.client.databases.update({ + database_id: database.id, + title: [ + { + text: { + content: 'Library', + }, + }, + ], + description: [ + { + text: { + content: 'Library of saved items from Omnivore', + }, + }, + ], + properties: { + Title: { + title: {}, + }, + Author: { + rich_text: {}, + }, + 'Original URL': { + url: {}, + }, + 'Omnivore URL': { + url: {}, + }, + 'Saved At': { + date: {}, + }, + 'Last Updated': { + date: {}, + }, + Tags: { + multi_select: {}, + }, + }, + }) + } }