diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index bf26872c5..bf7dc89f9 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -62,11 +62,11 @@ import { } from '../../services/labels' import { createLibraryItem, - findLibraryItemById, findLibraryItemByUrl, findLibraryItemsByPrefix, searchLibraryItems, updateLibraryItem, + updateLibraryItemReadingProgress, updateLibraryItems, } from '../../services/library_item' import { parsedContentToLibraryItem } from '../../services/save_page' @@ -572,14 +572,8 @@ export const saveArticleReadingProgressResolver = authorized< readingProgressTopPercent, }, }, - { uid, pubsub } + { log, pubsub, uid } ) => { - const libraryItem = await findLibraryItemById(id, uid) - - if (!libraryItem) { - return { errorCodes: [SaveArticleReadingProgressErrorCode.NotFound] } - } - if ( readingProgressPercent < 0 || readingProgressPercent > 100 || @@ -590,40 +584,26 @@ export const saveArticleReadingProgressResolver = authorized< ) { return { errorCodes: [SaveArticleReadingProgressErrorCode.BadData] } } - // If we have a top percent, we only save it if it's greater than the current top percent - // or set to zero if the top percent is zero. - const readingProgressTopPercentToSave = readingProgressTopPercent - ? Math.max( - readingProgressTopPercent, - libraryItem.readingProgressTopPercent || 0 - ) - : readingProgressTopPercent === 0 - ? 0 - : undefined - // If setting to zero we accept the update, otherwise we require it - // be greater than the current reading progress. - const updatedPart: QueryDeepPartialEntity = { - readingProgressBottomPercent: - readingProgressPercent === 0 - ? 0 - : Math.max( - readingProgressPercent, - libraryItem.readingProgressBottomPercent - ), - readingProgressHighestReadAnchor: - readingProgressAnchorIndex === 0 - ? 0 - : Math.max( - readingProgressAnchorIndex || 0, - libraryItem.readingProgressHighestReadAnchor - ), - readingProgressTopPercent: readingProgressTopPercentToSave, - readAt: new Date(), - } - const updatedItem = await updateLibraryItem(id, updatedPart, uid, pubsub) + try { + const updatedItem = await updateLibraryItemReadingProgress( + id, + uid, + readingProgressPercent, + readingProgressTopPercent, + readingProgressAnchorIndex, + pubsub + ) + if (!updatedItem) { + return { errorCodes: [SaveArticleReadingProgressErrorCode.BadData] } + } - return { - updatedArticle: libraryItemToArticle(updatedItem), + return { + updatedArticle: libraryItemToArticle(updatedItem), + } + } catch (error) { + log.error('saveArticleReadingProgressResolver error', error) + + return { errorCodes: [SaveArticleReadingProgressErrorCode.Unauthorized] } } } ) diff --git a/packages/api/src/services/library_item.ts b/packages/api/src/services/library_item.ts index 07be9f885..8dab74fc5 100644 --- a/packages/api/src/services/library_item.ts +++ b/packages/api/src/services/library_item.ts @@ -438,6 +438,75 @@ export const updateLibraryItem = async ( return updatedLibraryItem } +export const updateLibraryItemReadingProgress = async ( + id: string, + userId: string, + bottomPercent: number, + topPercent: number | null = null, + anchorIndex: number | null = null, + pubsub = createPubSubClient() +): Promise => { + // If we have a top percent, we only save it if it's greater than the current top percent + // or set to zero if the top percent is zero. + const result = (await authTrx( + async (tx) => + tx.getRepository(LibraryItem).query( + ` + UPDATE omnivore.library_item + SET reading_progress_top_percent = CASE + WHEN reading_progress_top_percent < $2 THEN $2 + WHEN $2 = 0 THEN 0 + ELSE reading_progress_top_percent + END, + reading_progress_bottom_percent = CASE + WHEN reading_progress_bottom_percent < $3 THEN $3 + WHEN $3 = 0 THEN 0 + ELSE reading_progress_bottom_percent + END, + reading_progress_highest_read_anchor = CASE + WHEN reading_progress_top_percent < $4 THEN $4 + WHEN $4 = 0 THEN 0 + ELSE reading_progress_highest_read_anchor + END, + read_at = now() + WHERE id = $1 AND ( + (reading_progress_top_percent < $2 OR $2 = 0) OR + (reading_progress_bottom_percent < $3 OR $3 = 0) OR + (reading_progress_highest_read_anchor < $4 OR $4 = 0) + ) + RETURNING + id, + reading_progress_top_percent as "readingProgressTopPercent", + reading_progress_bottom_percent as "readingProgressBottomPercent", + reading_progress_highest_read_anchor as "readingProgressHighestReadAnchor", + read_at as "readAt" + `, + [id, topPercent, bottomPercent, anchorIndex] + ), + undefined, + userId + )) as [LibraryItem[], number] + if (result[1] === 0) { + return null + } + + const updatedItem = result[0][0] + await pubsub.entityUpdated>( + EntityType.PAGE, + { + id, + readingProgressBottomPercent: updatedItem.readingProgressBottomPercent, + readingProgressTopPercent: updatedItem.readingProgressTopPercent, + readingProgressHighestReadAnchor: + updatedItem.readingProgressHighestReadAnchor, + readAt: updatedItem.readAt, + }, + userId + ) + + return updatedItem +} + export const createLibraryItems = async ( libraryItems: DeepPartial[], userId: string diff --git a/packages/api/test/resolvers/article.test.ts b/packages/api/test/resolvers/article.test.ts index e3b13c0d1..083bd389e 100644 --- a/packages/api/test/resolvers/article.test.ts +++ b/packages/api/test/resolvers/article.test.ts @@ -706,7 +706,6 @@ describe('Article API', () => { ).to.eq(75) // Now try to set to a lower value (50), value should not be updated - // refresh index to ensure the reading progress is updated const secondQuery = saveArticleReadingProgressQuery(itemId, 50) const secondRes = await graphqlRequest(secondQuery, authToken).expect(200) expect(