fix newsletters test
This commit is contained in:
@ -19,7 +19,7 @@ export class Integration {
|
|||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
id!: string
|
id!: string
|
||||||
|
|
||||||
@ManyToOne(() => User, { onDelete: 'CASCADE' })
|
@ManyToOne(() => User, { onDelete: 'CASCADE', eager: true })
|
||||||
@JoinColumn({ name: 'user_id' })
|
@JoinColumn({ name: 'user_id' })
|
||||||
user!: User
|
user!: User
|
||||||
|
|
||||||
|
|||||||
@ -102,7 +102,7 @@ export const markEmailAsItemResolver = authorized<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update received email type
|
// update received email type
|
||||||
await updateReceivedEmail(recentEmail.id, 'article')
|
await updateReceivedEmail(recentEmail.id, 'article', uid)
|
||||||
|
|
||||||
const text = `A recent email marked as a library item
|
const text = `A recent email marked as a library item
|
||||||
by: ${uid}
|
by: ${uid}
|
||||||
|
|||||||
@ -103,27 +103,24 @@ export function integrationsServiceRouter() {
|
|||||||
res.status(200).send('Bad Request')
|
res.status(200).send('Bad Request')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const page = await findLibraryItemById(id, userId)
|
const item = await findLibraryItemById(id, userId)
|
||||||
if (!page) {
|
if (!item) {
|
||||||
logger.info('No page found for id', { id })
|
logger.info('No item found for id', { id })
|
||||||
res.status(200).send('No page found')
|
res.status(200).send('No page found')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (page.user.id !== userId) {
|
|
||||||
logger.info('Page does not belong to user', { id, userId })
|
// sync updated item with integration
|
||||||
return res.status(200).send('Page does not belong to user')
|
logger.info('syncing updated item with integration', {
|
||||||
}
|
|
||||||
// sync updated page with integration
|
|
||||||
logger.info('syncing updated page with integration', {
|
|
||||||
integrationId: integration.id,
|
integrationId: integration.id,
|
||||||
pageId: page.id,
|
itemId: item.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
const synced = await integrationService.export(integration, [page])
|
const synced = await integrationService.export(integration, [item])
|
||||||
if (!synced) {
|
if (!synced) {
|
||||||
logger.info('failed to sync page', {
|
logger.info('failed to sync item', {
|
||||||
integrationId: integration.id,
|
integrationId: integration.id,
|
||||||
pageId: page.id,
|
itemId: item.id,
|
||||||
})
|
})
|
||||||
return res.status(400).send('Failed to sync')
|
return res.status(400).send('Failed to sync')
|
||||||
}
|
}
|
||||||
@ -135,7 +132,7 @@ export function integrationsServiceRouter() {
|
|||||||
let hasNextPage = true,
|
let hasNextPage = true,
|
||||||
count = 0,
|
count = 0,
|
||||||
after = 0,
|
after = 0,
|
||||||
pages: LibraryItem[] = [];
|
items: LibraryItem[] = [];
|
||||||
hasNextPage;
|
hasNextPage;
|
||||||
after += size, hasNextPage = count > after
|
after += size, hasNextPage = count > after
|
||||||
) {
|
) {
|
||||||
@ -148,15 +145,15 @@ export function integrationsServiceRouter() {
|
|||||||
{ from: after, size, dateFilters },
|
{ from: after, size, dateFilters },
|
||||||
userId
|
userId
|
||||||
)
|
)
|
||||||
pages = libraryItems
|
items = libraryItems
|
||||||
const pageIds = pages.map((p) => p.id)
|
const itemIds = items.map((p) => p.id)
|
||||||
|
|
||||||
logger.info('syncing pages', { pageIds })
|
logger.info('syncing items', { pageIds: itemIds })
|
||||||
|
|
||||||
const synced = await integrationService.export(integration, pages)
|
const synced = await integrationService.export(integration, items)
|
||||||
if (!synced) {
|
if (!synced) {
|
||||||
logger.error('failed to sync pages', {
|
logger.error('failed to sync items', {
|
||||||
pageIds,
|
pageIds: itemIds,
|
||||||
integrationId: integration.id,
|
integrationId: integration.id,
|
||||||
})
|
})
|
||||||
return res.status(400).send('Failed to sync')
|
return res.status(400).send('Failed to sync')
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import { updateIntegration } from '.'
|
||||||
import { HighlightType } from '../../entity/highlight'
|
import { HighlightType } from '../../entity/highlight'
|
||||||
import { Integration } from '../../entity/integration'
|
import { Integration } from '../../entity/integration'
|
||||||
import { LibraryItem } from '../../entity/library_item'
|
import { LibraryItem } from '../../entity/library_item'
|
||||||
@ -64,7 +65,7 @@ export class ReadwiseIntegration extends IntegrationService {
|
|||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
let result = true
|
let result = true
|
||||||
|
|
||||||
const highlights = items.flatMap(this.pageToReadwiseHighlight)
|
const highlights = items.flatMap(this.libraryItemToReadwiseHighlight)
|
||||||
// If there are no highlights, we will skip the sync
|
// If there are no highlights, we will skip the sync
|
||||||
if (highlights.length > 0) {
|
if (highlights.length > 0) {
|
||||||
result = await this.syncWithReadwise(integration.token, highlights)
|
result = await this.syncWithReadwise(integration.token, highlights)
|
||||||
@ -73,16 +74,18 @@ export class ReadwiseIntegration extends IntegrationService {
|
|||||||
// update integration syncedAt if successful
|
// update integration syncedAt if successful
|
||||||
if (result) {
|
if (result) {
|
||||||
logger.info('updating integration syncedAt')
|
logger.info('updating integration syncedAt')
|
||||||
await authTrx((t) =>
|
await updateIntegration(
|
||||||
t.getRepository(Integration).update(integration.id, {
|
integration.id,
|
||||||
|
{
|
||||||
syncedAt: new Date(),
|
syncedAt: new Date(),
|
||||||
})
|
},
|
||||||
|
integration.user.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
pageToReadwiseHighlight = (item: LibraryItem): ReadwiseHighlight[] => {
|
libraryItemToReadwiseHighlight = (item: LibraryItem): ReadwiseHighlight[] => {
|
||||||
if (!item.highlights) return []
|
if (!item.highlights) return []
|
||||||
const category = item.siteName === 'Twitter' ? 'tweets' : 'articles'
|
const category = item.siteName === 'Twitter' ? 'tweets' : 'articles'
|
||||||
return item.highlights
|
return item.highlights
|
||||||
@ -128,7 +131,7 @@ export class ReadwiseIntegration extends IntegrationService {
|
|||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Token ${token}`,
|
Authorization: `Token ${token}`,
|
||||||
ContentType: 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
timeout: 5000, // 5 seconds
|
timeout: 5000, // 5 seconds
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,23 +91,27 @@ export const addLabelsToLibraryItem = async (
|
|||||||
userId: string,
|
userId: string,
|
||||||
pubsub = createPubSubClient()
|
pubsub = createPubSubClient()
|
||||||
) => {
|
) => {
|
||||||
await authTrx(async (tx) => {
|
await authTrx(
|
||||||
const libraryItem = await tx
|
async (tx) => {
|
||||||
.withRepository(libraryItemRepository)
|
const libraryItem = await tx
|
||||||
.findOneByOrFail({ id: libraryItemId })
|
.withRepository(libraryItemRepository)
|
||||||
|
.findOneByOrFail({ id: libraryItemId })
|
||||||
|
|
||||||
if (libraryItem.labels) {
|
if (libraryItem.labels) {
|
||||||
labels.push(...libraryItem.labels)
|
labels.push(...libraryItem.labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
// save new labels
|
// save new labels
|
||||||
await tx.getRepository(EntityLabel).save(
|
await tx.getRepository(EntityLabel).save(
|
||||||
labels.map((l) => ({
|
labels.map((l) => ({
|
||||||
labelId: l.id,
|
labelId: l.id,
|
||||||
libraryItemId,
|
libraryItemId,
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
undefined,
|
||||||
|
userId
|
||||||
|
)
|
||||||
|
|
||||||
// create pubsub event
|
// create pubsub event
|
||||||
await pubsub.entityCreated<(Label & { pageId: string })[]>(
|
await pubsub.entityCreated<(Label & { pageId: string })[]>(
|
||||||
|
|||||||
@ -29,7 +29,7 @@ export const saveReceivedEmail = async (
|
|||||||
export const updateReceivedEmail = async (
|
export const updateReceivedEmail = async (
|
||||||
id: string,
|
id: string,
|
||||||
type: 'article' | 'non-article',
|
type: 'article' | 'non-article',
|
||||||
userId?: string
|
userId: string
|
||||||
) => {
|
) => {
|
||||||
return authTrx(
|
return authTrx(
|
||||||
(t) => t.getRepository(ReceivedEmail).update(id, { type }),
|
(t) => t.getRepository(ReceivedEmail).update(id, { type }),
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import {
|
|||||||
parsePreparedContent,
|
parsePreparedContent,
|
||||||
parseUrlMetadata,
|
parseUrlMetadata,
|
||||||
} from '../utils/parser'
|
} from '../utils/parser'
|
||||||
import { findOrCreateLabels } from './labels'
|
import { addLabelsToLibraryItem, findOrCreateLabels } from './labels'
|
||||||
import {
|
import {
|
||||||
createLibraryItem,
|
createLibraryItem,
|
||||||
findLibraryItemByUrl,
|
findLibraryItemByUrl,
|
||||||
@ -132,10 +132,11 @@ export const saveEmail = async (
|
|||||||
|
|
||||||
if (newsletterLabel) {
|
if (newsletterLabel) {
|
||||||
// add newsletter label
|
// add newsletter label
|
||||||
await findOrCreateLabels([newsletterLabel], input.userId)
|
const labels = await findOrCreateLabels([newsletterLabel], input.userId)
|
||||||
|
await addLabelsToLibraryItem(labels, newLibraryItem.id, input.userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateReceivedEmail(input.receivedEmailId, 'article')
|
await updateReceivedEmail(input.receivedEmailId, 'article', input.userId)
|
||||||
|
|
||||||
// create a task to update thumbnail and pre-cache all images
|
// create a task to update thumbnail and pre-cache all images
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -127,12 +127,12 @@ describe('Integrations routers', () => {
|
|||||||
let integration: Integration
|
let integration: Integration
|
||||||
let item: LibraryItem
|
let item: LibraryItem
|
||||||
let highlight: Highlight
|
let highlight: Highlight
|
||||||
let highlightsData: string
|
let highlightsData: any
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
integration = await saveIntegration(
|
integration = await saveIntegration(
|
||||||
{
|
{
|
||||||
user: { id: user.id },
|
user,
|
||||||
name: 'READWISE',
|
name: 'READWISE',
|
||||||
token: 'token',
|
token: 'token',
|
||||||
},
|
},
|
||||||
@ -157,24 +157,24 @@ describe('Integrations routers', () => {
|
|||||||
user.id
|
user.id
|
||||||
)
|
)
|
||||||
// create highlights data for integration request
|
// create highlights data for integration request
|
||||||
highlightsData = JSON.stringify({
|
highlightsData = {
|
||||||
highlights: [
|
highlights: [
|
||||||
{
|
{
|
||||||
text: highlight.quote,
|
text: highlight.quote,
|
||||||
title: item.title,
|
title: item.title,
|
||||||
author: item.author,
|
author: item.author ?? undefined,
|
||||||
highlight_url: getHighlightUrl(item.slug, highlight.id),
|
highlight_url: getHighlightUrl(item.slug, highlight.id),
|
||||||
highlighted_at: highlight.createdAt.toISOString(),
|
highlighted_at: highlight.createdAt.toISOString(),
|
||||||
category: 'articles',
|
category: 'articles',
|
||||||
image_url: item.thumbnail,
|
image_url: item.thumbnail ?? undefined,
|
||||||
// location: highlightPositionPercent,
|
// location: highlightPositionPercent,
|
||||||
location_type: 'order',
|
location_type: 'order',
|
||||||
note: highlight.annotation,
|
note: highlight.annotation ?? undefined,
|
||||||
source_type: 'omnivore',
|
source_type: 'omnivore',
|
||||||
source_url: item.originalUrl,
|
source_url: item.originalUrl,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
@ -205,7 +205,7 @@ describe('Integrations routers', () => {
|
|||||||
nock(READWISE_API_URL, {
|
nock(READWISE_API_URL, {
|
||||||
reqheaders: {
|
reqheaders: {
|
||||||
Authorization: `Token ${integration.token}`,
|
Authorization: `Token ${integration.token}`,
|
||||||
ContentType: 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.post('/highlights', highlightsData)
|
.post('/highlights', highlightsData)
|
||||||
@ -227,7 +227,7 @@ describe('Integrations routers', () => {
|
|||||||
nock(READWISE_API_URL, {
|
nock(READWISE_API_URL, {
|
||||||
reqheaders: {
|
reqheaders: {
|
||||||
Authorization: `Token ${integration.token}`,
|
Authorization: `Token ${integration.token}`,
|
||||||
ContentType: 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.post('/highlights')
|
.post('/highlights')
|
||||||
@ -236,7 +236,7 @@ describe('Integrations routers', () => {
|
|||||||
nock(READWISE_API_URL, {
|
nock(READWISE_API_URL, {
|
||||||
reqheaders: {
|
reqheaders: {
|
||||||
Authorization: `Token ${integration.token}`,
|
Authorization: `Token ${integration.token}`,
|
||||||
ContentType: 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.post('/highlights')
|
.post('/highlights')
|
||||||
@ -272,7 +272,7 @@ describe('Integrations routers', () => {
|
|||||||
nock(READWISE_API_URL, {
|
nock(READWISE_API_URL, {
|
||||||
reqheaders: {
|
reqheaders: {
|
||||||
Authorization: `Token ${integration.token}`,
|
Authorization: `Token ${integration.token}`,
|
||||||
ContentType: 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.post('/highlights', highlightsData)
|
.post('/highlights', highlightsData)
|
||||||
@ -306,7 +306,7 @@ describe('Integrations routers', () => {
|
|||||||
nock(READWISE_API_URL, {
|
nock(READWISE_API_URL, {
|
||||||
reqheaders: {
|
reqheaders: {
|
||||||
Authorization: `Token ${integration.token}`,
|
Authorization: `Token ${integration.token}`,
|
||||||
ContentType: 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.post('/highlights', highlightsData)
|
.post('/highlights', highlightsData)
|
||||||
|
|||||||
Reference in New Issue
Block a user