mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
export highlights and labels
This commit is contained in:
parent
ec32945ba2
commit
39778feb88
5 changed files with 175 additions and 41 deletions
|
|
@ -47,7 +47,7 @@ export const exportItem = async (jobData: ExportItemJobData) => {
|
|||
const client = getIntegrationClient(
|
||||
integration.name,
|
||||
integration.token,
|
||||
integration.settings
|
||||
integration
|
||||
)
|
||||
|
||||
const synced = await client.export(libraryItems)
|
||||
|
|
|
|||
|
|
@ -71,11 +71,7 @@ export const setIntegrationResolver = authorized<
|
|||
integrationToSave.taskName = existingIntegration.taskName
|
||||
} else {
|
||||
// Create
|
||||
const integrationService = getIntegrationClient(
|
||||
input.name,
|
||||
input.token,
|
||||
input.settings
|
||||
)
|
||||
const integrationService = getIntegrationClient(input.name, input.token)
|
||||
// authorize and get access token
|
||||
const token = await integrationService.accessToken()
|
||||
if (!token) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export function integrationRouter() {
|
|||
return res.status(401).send('UNAUTHORIZED')
|
||||
}
|
||||
|
||||
const integrationClient = getIntegrationClient(req.params.name, '', null)
|
||||
const integrationClient = getIntegrationClient(req.params.name, '')
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
const state = req.body.state as string
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { ReadwiseClient } from './readwise'
|
|||
export const getIntegrationClient = (
|
||||
name: string,
|
||||
token: string,
|
||||
settings: any
|
||||
integrationData?: Integration
|
||||
): IntegrationClient => {
|
||||
switch (name.toLowerCase()) {
|
||||
case 'readwise':
|
||||
|
|
@ -17,7 +17,7 @@ export const getIntegrationClient = (
|
|||
case 'pocket':
|
||||
return new PocketClient(token)
|
||||
case 'notion':
|
||||
return new NotionClient(token, settings)
|
||||
return new NotionClient(token, integrationData)
|
||||
default:
|
||||
throw new Error(`Integration client not found: ${name}`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,38 @@
|
|||
import { Client } from '@notionhq/client'
|
||||
import axios from 'axios'
|
||||
import { LibraryItem, LibraryItemState } from '../../entity/library_item'
|
||||
import { updateIntegration } from '.'
|
||||
import { Integration } from '../../entity/integration'
|
||||
import { LibraryItem } from '../../entity/library_item'
|
||||
import { env } from '../../env'
|
||||
import { Merge } from '../../util'
|
||||
import { logger } from '../../utils/logger'
|
||||
import { IntegrationClient } from './integration'
|
||||
|
||||
type AnnotationColor =
|
||||
| 'default'
|
||||
| 'gray'
|
||||
| 'brown'
|
||||
| 'orange'
|
||||
| 'yellow'
|
||||
| 'green'
|
||||
| 'blue'
|
||||
| 'purple'
|
||||
| 'pink'
|
||||
| 'red'
|
||||
| 'gray_background'
|
||||
| 'brown_background'
|
||||
| 'orange_background'
|
||||
| 'yellow_background'
|
||||
| 'green_background'
|
||||
| 'blue_background'
|
||||
| 'purple_background'
|
||||
| 'pink_background'
|
||||
| 'red_background'
|
||||
|
||||
interface NotionPage {
|
||||
parent: {
|
||||
database_id: string
|
||||
}
|
||||
id: string
|
||||
created_time: string
|
||||
last_edited_time: string
|
||||
archived: boolean
|
||||
public_url: string
|
||||
cover?: {
|
||||
external: {
|
||||
url: string
|
||||
|
|
@ -25,20 +44,48 @@ interface NotionPage {
|
|||
}
|
||||
}
|
||||
properties: {
|
||||
title: [
|
||||
{
|
||||
text: {
|
||||
content: string
|
||||
link: {
|
||||
url: string
|
||||
Title: {
|
||||
title: [
|
||||
{
|
||||
text: {
|
||||
content: string
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
'Original URL': {
|
||||
url: string | null
|
||||
}
|
||||
'Omnivore URL': {
|
||||
url: string | null
|
||||
}
|
||||
Tags?: {
|
||||
multi_select: Array<{ name: string }>
|
||||
}
|
||||
}
|
||||
children?: Array<{
|
||||
type: 'paragraph'
|
||||
paragraph: {
|
||||
rich_text: Array<{
|
||||
text: {
|
||||
content: string
|
||||
link?: { url: string }
|
||||
}
|
||||
annotations?: {
|
||||
bold?: boolean
|
||||
italic?: boolean
|
||||
strikethrough?: boolean
|
||||
underline?: boolean
|
||||
code?: boolean
|
||||
color?: AnnotationColor
|
||||
}
|
||||
}>
|
||||
}
|
||||
}>
|
||||
}
|
||||
|
||||
interface Settings {
|
||||
parentPageId: string
|
||||
parentDatabaseId: string
|
||||
}
|
||||
|
||||
|
|
@ -57,15 +104,15 @@ export class NotionClient implements IntegrationClient {
|
|||
|
||||
_token: string
|
||||
_client: Client
|
||||
_settings: Settings
|
||||
_integrationData?: Merge<Integration, { settings?: Settings }>
|
||||
|
||||
constructor(token: string, settings: Settings) {
|
||||
constructor(token: string, integration?: Integration) {
|
||||
this._token = token
|
||||
this._client = new Client({
|
||||
auth: token,
|
||||
timeoutMs: this._timeout,
|
||||
})
|
||||
this._settings = settings
|
||||
this._integrationData = integration
|
||||
}
|
||||
|
||||
accessToken = async (): Promise<string | null> => {
|
||||
|
|
@ -105,15 +152,15 @@ export class NotionClient implements IntegrationClient {
|
|||
}
|
||||
|
||||
private _itemToNotionPage = (item: LibraryItem): NotionPage => {
|
||||
const databaseId = this._integrationData?.settings?.parentDatabaseId
|
||||
if (!databaseId) {
|
||||
throw new Error('Notion database id not found')
|
||||
}
|
||||
|
||||
return {
|
||||
parent: {
|
||||
database_id: this._settings.parentDatabaseId,
|
||||
database_id: databaseId,
|
||||
},
|
||||
id: item.id,
|
||||
archived: item.state === LibraryItemState.Archived,
|
||||
created_time: item.savedAt.toISOString(),
|
||||
last_edited_time: item.updatedAt.toISOString(),
|
||||
public_url: item.originalUrl,
|
||||
icon: item.siteIcon
|
||||
? {
|
||||
external: {
|
||||
|
|
@ -129,17 +176,50 @@ export class NotionClient implements IntegrationClient {
|
|||
}
|
||||
: undefined,
|
||||
properties: {
|
||||
title: [
|
||||
{
|
||||
text: {
|
||||
content: item.title,
|
||||
link: {
|
||||
url: item.originalUrl,
|
||||
Title: {
|
||||
title: [
|
||||
{
|
||||
text: {
|
||||
content: item.title,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'Original URL': {
|
||||
url: item.originalUrl,
|
||||
},
|
||||
'Omnivore URL': {
|
||||
url: `${env.client.url}/me/${item.slug}`,
|
||||
},
|
||||
Tags: item.labels
|
||||
? { multi_select: item.labels.map((label) => ({ name: label.name })) }
|
||||
: undefined,
|
||||
},
|
||||
children: item.highlights
|
||||
? item.highlights.map((highlight) => ({
|
||||
type: 'paragraph',
|
||||
paragraph: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: highlight.quote || '',
|
||||
},
|
||||
annotations: {
|
||||
color: highlight.color as AnnotationColor,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: {
|
||||
content: highlight.annotation || '',
|
||||
},
|
||||
annotations: {
|
||||
italic: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}))
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -148,8 +228,66 @@ export class NotionClient implements IntegrationClient {
|
|||
}
|
||||
|
||||
export = async (items: LibraryItem[]): Promise<boolean> => {
|
||||
if (!this._integrationData || !this._integrationData.settings) {
|
||||
logger.error('Notion integration data not found')
|
||||
return false
|
||||
}
|
||||
|
||||
const pageId = this._integrationData.settings.parentPageId
|
||||
if (!pageId) {
|
||||
logger.error('Notion parent page id not found')
|
||||
return false
|
||||
}
|
||||
|
||||
const databaseId = this._integrationData.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: {},
|
||||
},
|
||||
'Original URL': {
|
||||
url: {},
|
||||
},
|
||||
'Omnivore URL': {
|
||||
url: {},
|
||||
},
|
||||
Tags: {
|
||||
multi_select: {},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// save the database id
|
||||
this._integrationData.settings.parentDatabaseId = database.id
|
||||
await updateIntegration(
|
||||
this._integrationData.id,
|
||||
{
|
||||
settings: this._integrationData.settings,
|
||||
},
|
||||
this._integrationData.user.id
|
||||
)
|
||||
}
|
||||
|
||||
const pages = items.map(this._itemToNotionPage)
|
||||
console.log('pages', JSON.stringify(pages, null, 2))
|
||||
await Promise.all(pages.map((page) => this._createPage(page)))
|
||||
|
||||
return true
|
||||
|
|
|
|||
Loading…
Reference in a new issue