From cbaa3d69009fca993346f6b4c993493fa76ecca8 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 12 Sep 2023 22:42:49 +0900 Subject: [PATCH] fix newsletters test --- packages/api/src/entity/integration.ts | 2 +- .../api/src/resolvers/recent_emails/index.ts | 2 +- packages/api/src/routers/svc/integrations.ts | 37 +++++++++---------- .../api/src/services/integrations/readwise.ts | 15 +++++--- packages/api/src/services/labels.ts | 34 +++++++++-------- packages/api/src/services/received_emails.ts | 2 +- packages/api/src/services/save_email.ts | 7 ++-- .../api/test/routers/integrations.test.ts | 24 ++++++------ 8 files changed, 64 insertions(+), 59 deletions(-) diff --git a/packages/api/src/entity/integration.ts b/packages/api/src/entity/integration.ts index a051ac0db..8f03d455a 100644 --- a/packages/api/src/entity/integration.ts +++ b/packages/api/src/entity/integration.ts @@ -19,7 +19,7 @@ export class Integration { @PrimaryGeneratedColumn('uuid') id!: string - @ManyToOne(() => User, { onDelete: 'CASCADE' }) + @ManyToOne(() => User, { onDelete: 'CASCADE', eager: true }) @JoinColumn({ name: 'user_id' }) user!: User diff --git a/packages/api/src/resolvers/recent_emails/index.ts b/packages/api/src/resolvers/recent_emails/index.ts index 7833533e6..d61731a3e 100644 --- a/packages/api/src/resolvers/recent_emails/index.ts +++ b/packages/api/src/resolvers/recent_emails/index.ts @@ -102,7 +102,7 @@ export const markEmailAsItemResolver = authorized< } // 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 by: ${uid} diff --git a/packages/api/src/routers/svc/integrations.ts b/packages/api/src/routers/svc/integrations.ts index 3e89b5d13..d06c2d44e 100644 --- a/packages/api/src/routers/svc/integrations.ts +++ b/packages/api/src/routers/svc/integrations.ts @@ -103,27 +103,24 @@ export function integrationsServiceRouter() { res.status(200).send('Bad Request') return } - const page = await findLibraryItemById(id, userId) - if (!page) { - logger.info('No page found for id', { id }) + const item = await findLibraryItemById(id, userId) + if (!item) { + logger.info('No item found for id', { id }) res.status(200).send('No page found') return } - if (page.user.id !== userId) { - logger.info('Page does not belong to user', { id, userId }) - return res.status(200).send('Page does not belong to user') - } - // sync updated page with integration - logger.info('syncing updated page with integration', { + + // sync updated item with integration + logger.info('syncing updated item with integration', { 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) { - logger.info('failed to sync page', { + logger.info('failed to sync item', { integrationId: integration.id, - pageId: page.id, + itemId: item.id, }) return res.status(400).send('Failed to sync') } @@ -135,7 +132,7 @@ export function integrationsServiceRouter() { let hasNextPage = true, count = 0, after = 0, - pages: LibraryItem[] = []; + items: LibraryItem[] = []; hasNextPage; after += size, hasNextPage = count > after ) { @@ -148,15 +145,15 @@ export function integrationsServiceRouter() { { from: after, size, dateFilters }, userId ) - pages = libraryItems - const pageIds = pages.map((p) => p.id) + items = libraryItems + 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) { - logger.error('failed to sync pages', { - pageIds, + logger.error('failed to sync items', { + pageIds: itemIds, integrationId: integration.id, }) return res.status(400).send('Failed to sync') diff --git a/packages/api/src/services/integrations/readwise.ts b/packages/api/src/services/integrations/readwise.ts index 78e243dd5..3939530a2 100644 --- a/packages/api/src/services/integrations/readwise.ts +++ b/packages/api/src/services/integrations/readwise.ts @@ -1,4 +1,5 @@ import axios from 'axios' +import { updateIntegration } from '.' import { HighlightType } from '../../entity/highlight' import { Integration } from '../../entity/integration' import { LibraryItem } from '../../entity/library_item' @@ -64,7 +65,7 @@ export class ReadwiseIntegration extends IntegrationService { ): Promise => { 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 (highlights.length > 0) { result = await this.syncWithReadwise(integration.token, highlights) @@ -73,16 +74,18 @@ export class ReadwiseIntegration extends IntegrationService { // update integration syncedAt if successful if (result) { logger.info('updating integration syncedAt') - await authTrx((t) => - t.getRepository(Integration).update(integration.id, { + await updateIntegration( + integration.id, + { syncedAt: new Date(), - }) + }, + integration.user.id ) } return result } - pageToReadwiseHighlight = (item: LibraryItem): ReadwiseHighlight[] => { + libraryItemToReadwiseHighlight = (item: LibraryItem): ReadwiseHighlight[] => { if (!item.highlights) return [] const category = item.siteName === 'Twitter' ? 'tweets' : 'articles' return item.highlights @@ -128,7 +131,7 @@ export class ReadwiseIntegration extends IntegrationService { { headers: { Authorization: `Token ${token}`, - ContentType: 'application/json', + 'Content-Type': 'application/json', }, timeout: 5000, // 5 seconds } diff --git a/packages/api/src/services/labels.ts b/packages/api/src/services/labels.ts index 2197aecb0..2879d6faa 100644 --- a/packages/api/src/services/labels.ts +++ b/packages/api/src/services/labels.ts @@ -91,23 +91,27 @@ export const addLabelsToLibraryItem = async ( userId: string, pubsub = createPubSubClient() ) => { - await authTrx(async (tx) => { - const libraryItem = await tx - .withRepository(libraryItemRepository) - .findOneByOrFail({ id: libraryItemId }) + await authTrx( + async (tx) => { + const libraryItem = await tx + .withRepository(libraryItemRepository) + .findOneByOrFail({ id: libraryItemId }) - if (libraryItem.labels) { - labels.push(...libraryItem.labels) - } + if (libraryItem.labels) { + labels.push(...libraryItem.labels) + } - // save new labels - await tx.getRepository(EntityLabel).save( - labels.map((l) => ({ - labelId: l.id, - libraryItemId, - })) - ) - }) + // save new labels + await tx.getRepository(EntityLabel).save( + labels.map((l) => ({ + labelId: l.id, + libraryItemId, + })) + ) + }, + undefined, + userId + ) // create pubsub event await pubsub.entityCreated<(Label & { pageId: string })[]>( diff --git a/packages/api/src/services/received_emails.ts b/packages/api/src/services/received_emails.ts index 98930d9fa..0551a28b1 100644 --- a/packages/api/src/services/received_emails.ts +++ b/packages/api/src/services/received_emails.ts @@ -29,7 +29,7 @@ export const saveReceivedEmail = async ( export const updateReceivedEmail = async ( id: string, type: 'article' | 'non-article', - userId?: string + userId: string ) => { return authTrx( (t) => t.getRepository(ReceivedEmail).update(id, { type }), diff --git a/packages/api/src/services/save_email.ts b/packages/api/src/services/save_email.ts index 0aa53a6dc..1c5976023 100644 --- a/packages/api/src/services/save_email.ts +++ b/packages/api/src/services/save_email.ts @@ -20,7 +20,7 @@ import { parsePreparedContent, parseUrlMetadata, } from '../utils/parser' -import { findOrCreateLabels } from './labels' +import { addLabelsToLibraryItem, findOrCreateLabels } from './labels' import { createLibraryItem, findLibraryItemByUrl, @@ -132,10 +132,11 @@ export const saveEmail = async ( if (newsletterLabel) { // 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 try { diff --git a/packages/api/test/routers/integrations.test.ts b/packages/api/test/routers/integrations.test.ts index 7d3db5ab7..9081ef2f3 100644 --- a/packages/api/test/routers/integrations.test.ts +++ b/packages/api/test/routers/integrations.test.ts @@ -127,12 +127,12 @@ describe('Integrations routers', () => { let integration: Integration let item: LibraryItem let highlight: Highlight - let highlightsData: string + let highlightsData: any before(async () => { integration = await saveIntegration( { - user: { id: user.id }, + user, name: 'READWISE', token: 'token', }, @@ -157,24 +157,24 @@ describe('Integrations routers', () => { user.id ) // create highlights data for integration request - highlightsData = JSON.stringify({ + highlightsData = { highlights: [ { text: highlight.quote, title: item.title, - author: item.author, + author: item.author ?? undefined, highlight_url: getHighlightUrl(item.slug, highlight.id), highlighted_at: highlight.createdAt.toISOString(), category: 'articles', - image_url: item.thumbnail, + image_url: item.thumbnail ?? undefined, // location: highlightPositionPercent, location_type: 'order', - note: highlight.annotation, + note: highlight.annotation ?? undefined, source_type: 'omnivore', source_url: item.originalUrl, }, ], - }) + } }) after(async () => { @@ -205,7 +205,7 @@ describe('Integrations routers', () => { nock(READWISE_API_URL, { reqheaders: { Authorization: `Token ${integration.token}`, - ContentType: 'application/json', + 'Content-Type': 'application/json', }, }) .post('/highlights', highlightsData) @@ -227,7 +227,7 @@ describe('Integrations routers', () => { nock(READWISE_API_URL, { reqheaders: { Authorization: `Token ${integration.token}`, - ContentType: 'application/json', + 'Content-Type': 'application/json', }, }) .post('/highlights') @@ -236,7 +236,7 @@ describe('Integrations routers', () => { nock(READWISE_API_URL, { reqheaders: { Authorization: `Token ${integration.token}`, - ContentType: 'application/json', + 'Content-Type': 'application/json', }, }) .post('/highlights') @@ -272,7 +272,7 @@ describe('Integrations routers', () => { nock(READWISE_API_URL, { reqheaders: { Authorization: `Token ${integration.token}`, - ContentType: 'application/json', + 'Content-Type': 'application/json', }, }) .post('/highlights', highlightsData) @@ -306,7 +306,7 @@ describe('Integrations routers', () => { nock(READWISE_API_URL, { reqheaders: { Authorization: `Token ${integration.token}`, - ContentType: 'application/json', + 'Content-Type': 'application/json', }, }) .post('/highlights', highlightsData)