mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
read settings
This commit is contained in:
parent
69e74d432d
commit
1085dcc824
4 changed files with 125 additions and 107 deletions
|
|
@ -20,7 +20,7 @@ export interface RetrieveRequest {
|
|||
|
||||
export interface IntegrationClient {
|
||||
name: string
|
||||
_token: string
|
||||
token: string
|
||||
|
||||
accessToken(): Promise<string | null>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { Integration } from '../../entity/integration'
|
|||
import { LibraryItem } from '../../entity/library_item'
|
||||
import { env } from '../../env'
|
||||
import { Merge } from '../../util'
|
||||
import { highlightUrl } from '../../utils/helpers'
|
||||
import { logger } from '../../utils/logger'
|
||||
import { IntegrationClient } from './integration'
|
||||
|
||||
|
|
@ -91,35 +92,39 @@ interface NotionPage {
|
|||
}>
|
||||
}
|
||||
|
||||
type Property = 'highlights' | 'labels' | 'notes'
|
||||
|
||||
interface Settings {
|
||||
parentPageId: string
|
||||
parentDatabaseId: string
|
||||
properties: Property[]
|
||||
}
|
||||
|
||||
export class NotionClient implements IntegrationClient {
|
||||
name = 'NOTION'
|
||||
_headers = {
|
||||
token: string
|
||||
|
||||
private headers = {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
'Notion-Version': '2022-06-28',
|
||||
}
|
||||
_timeout = 5000 // 5 seconds
|
||||
_axios = axios.create({
|
||||
private timeout = 5000 // 5 seconds
|
||||
private axiosInstance = axios.create({
|
||||
baseURL: 'https://api.notion.com/v1',
|
||||
timeout: this._timeout,
|
||||
timeout: this.timeout,
|
||||
})
|
||||
|
||||
_token: string
|
||||
_client: Client
|
||||
_integrationData?: Merge<Integration, { settings?: Settings }>
|
||||
private client: Client
|
||||
private integrationData?: Merge<Integration, { settings?: Settings }>
|
||||
|
||||
constructor(token: string, integration?: Integration) {
|
||||
this._token = token
|
||||
this._client = new Client({
|
||||
this.token = token
|
||||
this.client = new Client({
|
||||
auth: token,
|
||||
timeoutMs: this._timeout,
|
||||
timeoutMs: this.timeout,
|
||||
})
|
||||
this._integrationData = integration
|
||||
this.integrationData = integration
|
||||
}
|
||||
|
||||
accessToken = async (): Promise<string | null> => {
|
||||
|
|
@ -129,16 +134,16 @@ export class NotionClient implements IntegrationClient {
|
|||
`${env.notion.clientId}:${env.notion.clientSecret}`
|
||||
).toString('base64')
|
||||
|
||||
const response = await this._axios.post<{ access_token: string }>(
|
||||
const response = await this.axiosInstance.post<{ access_token: string }>(
|
||||
'/oauth/token',
|
||||
{
|
||||
grant_type: 'authorization_code',
|
||||
code: this._token,
|
||||
code: this.token,
|
||||
redirect_uri: `${env.client.url}/settings/integrations`,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
...this._headers,
|
||||
...this.headers,
|
||||
Authorization: `Basic ${encoded}`,
|
||||
},
|
||||
}
|
||||
|
|
@ -160,90 +165,101 @@ export class NotionClient implements IntegrationClient {
|
|||
|
||||
private itemToNotionPage = (
|
||||
item: LibraryItem,
|
||||
databaseId: string
|
||||
): NotionPage => ({
|
||||
parent: {
|
||||
database_id: databaseId,
|
||||
},
|
||||
icon: item.siteIcon
|
||||
? {
|
||||
external: {
|
||||
url: item.siteIcon,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
cover: item.thumbnail
|
||||
? {
|
||||
external: {
|
||||
url: item.thumbnail,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
properties: {
|
||||
Title: {
|
||||
title: [
|
||||
{
|
||||
text: {
|
||||
content: item.title,
|
||||
settings: Settings
|
||||
): NotionPage => {
|
||||
return {
|
||||
parent: {
|
||||
database_id: settings.parentDatabaseId,
|
||||
},
|
||||
icon: item.siteIcon
|
||||
? {
|
||||
external: {
|
||||
url: item.siteIcon,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
Author: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: item.author || 'unknown',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
'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 || '',
|
||||
link: {
|
||||
url: `${env.client.url}/me/${item.slug}#${highlight.id}`,
|
||||
cover: item.thumbnail
|
||||
? {
|
||||
external: {
|
||||
url: item.thumbnail,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
properties: {
|
||||
Title: {
|
||||
title: [
|
||||
{
|
||||
text: {
|
||||
content: item.title,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
Author: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: item.author || 'unknown',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
'Original URL': {
|
||||
url: item.originalUrl,
|
||||
},
|
||||
'Omnivore URL': {
|
||||
url: `${env.client.url}/me/${item.slug}`,
|
||||
},
|
||||
Tags:
|
||||
item.labels && settings.properties.includes('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: settings.properties.includes('highlights')
|
||||
? highlight.quote || ''
|
||||
: '',
|
||||
link: {
|
||||
url: highlightUrl(item.slug, highlight.id),
|
||||
},
|
||||
},
|
||||
annotations: {
|
||||
color: highlight.color as AnnotationColor,
|
||||
},
|
||||
},
|
||||
annotations: {
|
||||
color: highlight.color as AnnotationColor,
|
||||
{
|
||||
text: {
|
||||
content: settings.properties.includes('notes')
|
||||
? `\n${highlight.annotation || ''}`
|
||||
: '',
|
||||
},
|
||||
annotations: {
|
||||
italic: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text: {
|
||||
content: `\n${highlight.annotation || ''}`,
|
||||
},
|
||||
annotations: {
|
||||
italic: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}))
|
||||
: undefined,
|
||||
})
|
||||
],
|
||||
},
|
||||
}))
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
private createPage = async (page: NotionPage) => {
|
||||
await this._client.pages.create(page)
|
||||
await this.client.pages.create(page)
|
||||
}
|
||||
|
||||
private findPage = async (url: string, databaseId: string) => {
|
||||
const response = await this._client.databases.query({
|
||||
const response = await this.client.databases.query({
|
||||
database_id: databaseId,
|
||||
page_size: 1,
|
||||
filter: {
|
||||
|
|
@ -261,21 +277,22 @@ export class NotionClient implements IntegrationClient {
|
|||
}
|
||||
|
||||
export = async (items: LibraryItem[]): Promise<boolean> => {
|
||||
if (!this._integrationData || !this._integrationData.settings) {
|
||||
const settings = this.integrationData?.settings
|
||||
if (!this.integrationData || !settings) {
|
||||
logger.error('Notion integration data not found')
|
||||
return false
|
||||
}
|
||||
|
||||
const pageId = this._integrationData.settings.parentPageId
|
||||
const pageId = settings.parentPageId
|
||||
if (!pageId) {
|
||||
logger.error('Notion parent page id not found')
|
||||
return false
|
||||
}
|
||||
|
||||
let databaseId = this._integrationData.settings.parentDatabaseId
|
||||
let databaseId = settings.parentDatabaseId
|
||||
if (!databaseId) {
|
||||
// create a database for the items
|
||||
const database = await this._client.databases.create({
|
||||
const database = await this.client.databases.create({
|
||||
parent: {
|
||||
page_id: pageId,
|
||||
},
|
||||
|
|
@ -315,33 +332,33 @@ export class NotionClient implements IntegrationClient {
|
|||
// save the database id
|
||||
databaseId = database.id
|
||||
await updateIntegration(
|
||||
this._integrationData.id,
|
||||
this.integrationData.id,
|
||||
{
|
||||
settings: {
|
||||
...this._integrationData.settings,
|
||||
...this.integrationData.settings,
|
||||
parentDatabaseId: databaseId,
|
||||
},
|
||||
},
|
||||
this._integrationData.user.id
|
||||
this.integrationData.user.id
|
||||
)
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
items.map(async (item) => {
|
||||
const notionPage = this.itemToNotionPage(item, databaseId)
|
||||
const notionPage = this.itemToNotionPage(item, settings)
|
||||
const url = notionPage.properties['Omnivore URL'].url
|
||||
|
||||
const existingPage = await this.findPage(url, databaseId)
|
||||
if (existingPage) {
|
||||
// update the page
|
||||
await this._client.pages.update({
|
||||
await this.client.pages.update({
|
||||
page_id: existingPage.id,
|
||||
properties: notionPage.properties,
|
||||
})
|
||||
|
||||
// append the children
|
||||
if (notionPage.children) {
|
||||
await this._client.blocks.children.append({
|
||||
await this.client.blocks.children.append({
|
||||
block_id: existingPage.id,
|
||||
children: notionPage.children,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { IntegrationClient } from './integration'
|
|||
|
||||
export class PocketClient implements IntegrationClient {
|
||||
name = 'POCKET'
|
||||
_token: string
|
||||
token: string
|
||||
_axios = axios.create({
|
||||
baseURL: 'https://getpocket.com/v3',
|
||||
headers: {
|
||||
|
|
@ -16,7 +16,7 @@ export class PocketClient implements IntegrationClient {
|
|||
})
|
||||
|
||||
constructor(token: string) {
|
||||
this._token = token
|
||||
this.token = token
|
||||
}
|
||||
|
||||
accessToken = async (): Promise<string | null> => {
|
||||
|
|
@ -25,7 +25,7 @@ export class PocketClient implements IntegrationClient {
|
|||
'/oauth/authorize',
|
||||
{
|
||||
consumer_key: env.pocket.consumerKey,
|
||||
code: this._token,
|
||||
code: this.token,
|
||||
}
|
||||
)
|
||||
return response.data.access_token
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ interface ReadwiseHighlight {
|
|||
|
||||
export class ReadwiseClient implements IntegrationClient {
|
||||
name = 'READWISE'
|
||||
token: string
|
||||
|
||||
_headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
|
|
@ -40,10 +42,9 @@ export class ReadwiseClient implements IntegrationClient {
|
|||
baseURL: 'https://readwise.io/api/v2',
|
||||
timeout: 5000, // 5 seconds
|
||||
})
|
||||
_token: string
|
||||
|
||||
constructor(token: string) {
|
||||
this._token = token
|
||||
this.token = token
|
||||
}
|
||||
|
||||
accessToken = async (): Promise<string | null> => {
|
||||
|
|
@ -51,10 +52,10 @@ export class ReadwiseClient implements IntegrationClient {
|
|||
const response = await this._axios.get('/auth', {
|
||||
headers: {
|
||||
...this._headers,
|
||||
Authorization: `Token ${this._token}`,
|
||||
Authorization: `Token ${this.token}`,
|
||||
},
|
||||
})
|
||||
return response.status === 204 ? this._token : null
|
||||
return response.status === 204 ? this.token : null
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
logger.error(error.response)
|
||||
|
|
@ -121,7 +122,7 @@ export class ReadwiseClient implements IntegrationClient {
|
|||
{
|
||||
headers: {
|
||||
...this._headers,
|
||||
Authorization: `Token ${this._token}`,
|
||||
Authorization: `Token ${this.token}`,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue