fix newsletters test
This commit is contained in:
@ -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
|
||||
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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')
|
||||
|
||||
@ -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<boolean> => {
|
||||
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
|
||||
}
|
||||
|
||||
@ -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 })[]>(
|
||||
|
||||
@ -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 }),
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user