diff --git a/packages/api/src/routers/svc/following.ts b/packages/api/src/routers/svc/following.ts index 3e0b0eedb..261dbf4ee 100644 --- a/packages/api/src/routers/svc/following.ts +++ b/packages/api/src/routers/svc/following.ts @@ -5,7 +5,6 @@ import { PageType, PreparedDocumentInput, } from '../../generated/graphql' -import { isUniqueViolation } from '../../repository' import { createAndSaveLabelsInLibraryItem } from '../../services/labels' import { createLibraryItem } from '../../services/library_item' import { parsedContentToLibraryItem } from '../../services/save_page' @@ -126,29 +125,18 @@ export function followingServiceRouter() { state: ArticleSavingRequestStatus.ContentNotFetched, }) - try { - const newItem = await createLibraryItem(itemToSave, userId) - logger.info('feed item saved in following') + const newItem = await createLibraryItem(itemToSave, userId) + logger.info('feed item saved in following') - // save RSS label in the item - await createAndSaveLabelsInLibraryItem( - newItem.id, - userId, - [{ name: 'RSS' }], - feedUrl - ) + // save RSS label in the item + await createAndSaveLabelsInLibraryItem( + newItem.id, + userId, + [{ name: 'RSS' }], + feedUrl + ) - logger.info('RSS label added to the item') - } catch (error) { - if (isUniqueViolation(error)) { - logger.info('feed item already saved') - return res.sendStatus(200) - } - - logger.error('error saving feed item', error) - - return res.sendStatus(500) - } + logger.info('RSS label added to the item') return res.sendStatus(200) } diff --git a/packages/api/src/services/library_item.ts b/packages/api/src/services/library_item.ts index be5a9d4e4..11a7ee92a 100644 --- a/packages/api/src/services/library_item.ts +++ b/packages/api/src/services/library_item.ts @@ -8,16 +8,18 @@ import { Label } from '../entity/label' import { LibraryItem, LibraryItemState } from '../entity/library_item' import { BulkActionType, InputMaybe, SortParams } from '../generated/graphql' import { createPubSubClient, EntityType } from '../pubsub' +import { redisDataSource } from '../redis_data_source' import { authTrx, getColumns, + isUniqueViolation, queryBuilderToRawSql, valuesToRawSql, } from '../repository' import { libraryItemRepository } from '../repository/library_item' import { setRecentlySavedItemInRedis, wordsCount } from '../utils/helpers' +import { logger } from '../utils/logger' import { parseSearchQuery } from '../utils/search' -import { redisDataSource } from '../redis_data_source' enum ReadFilter { ALL = 'all', @@ -811,43 +813,68 @@ export const createLibraryItem = async ( pubsub = createPubSubClient(), skipPubSub = false ): Promise => { - const newLibraryItem = await authTrx( - async (tx) => - tx.withRepository(libraryItemRepository).save({ - ...libraryItem, - wordCount: - libraryItem.wordCount ?? - wordsCount(libraryItem.readableContent || ''), - }), - undefined, - userId - ) + if (!libraryItem.originalUrl) { + throw new Error('Original url is required') + } - // set recently saved item in redis if redis is enabled - if (redisDataSource.redisClient) { - await setRecentlySavedItemInRedis( - redisDataSource.redisClient, - userId, - newLibraryItem.originalUrl + try { + const newLibraryItem = await authTrx( + async (tx) => + tx.withRepository(libraryItemRepository).save({ + ...libraryItem, + wordCount: + libraryItem.wordCount ?? + wordsCount(libraryItem.readableContent || ''), + }), + undefined, + userId + ) + logger.info('item created', { url: libraryItem.originalUrl }) + + // set recently saved item in redis if redis is enabled + if (redisDataSource.redisClient) { + await setRecentlySavedItemInRedis( + redisDataSource.redisClient, + userId, + newLibraryItem.originalUrl + ) + } + + if (skipPubSub) { + return newLibraryItem + } + + await pubsub.entityCreated>( + EntityType.PAGE, + { + ...newLibraryItem, + // don't send original content and readable content + originalContent: undefined, + readableContent: undefined, + }, + userId ) - } - if (skipPubSub) { return newLibraryItem + } catch (error) { + if (isUniqueViolation(error)) { + logger.info('item already created', { url: libraryItem.originalUrl }) + + const existingItem = await findLibraryItemByUrl( + libraryItem.originalUrl, + userId + ) + + if (!existingItem) { + throw new Error(`Item not found for url: ${libraryItem.originalUrl}`) + } + + return existingItem + } + + logger.error('error creating item', error) + throw error } - - await pubsub.entityCreated>( - EntityType.PAGE, - { - ...newLibraryItem, - // don't send original content and readable content - originalContent: undefined, - readableContent: undefined, - }, - userId - ) - - return newLibraryItem } export const findLibraryItemsByPrefix = async ( diff --git a/packages/api/test/db.ts b/packages/api/test/db.ts index d7ed692d9..26a02e965 100644 --- a/packages/api/test/db.ts +++ b/packages/api/test/db.ts @@ -106,7 +106,7 @@ export const createTestLibraryItem = async ( userId: string, labels?: Label[] ): Promise => { - const item: DeepPartial = { + const item = { user: { id: userId }, title: 'test title', originalContent: '

test content

',