diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index 5891179fe..3a915006a 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -5,13 +5,13 @@ /* eslint-disable @typescript-eslint/no-floating-promises */ import { Readability } from '@omnivore/readability' import graphqlFields from 'graphql-fields' -import { DeepPartial } from 'typeorm' +import { Not } from 'typeorm' +import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity' import { LibraryItem, LibraryItemState } from '../../entity/library_item' import { env } from '../../env' import { ArticleError, ArticleErrorCode, - ArticleSavingRequestStatus, ArticleSuccess, BulkActionError, BulkActionErrorCode, @@ -58,6 +58,7 @@ import { addLabelsToLibraryItem, findLabelsByIds, findOrCreateLabels, + saveLabelsInLibraryItem, } from '../../services/labels' import { createLibraryItem, @@ -287,6 +288,7 @@ export const createArticleResolver = authorized< uploadFileHash, canonicalUrl, uploadFileId, + state, }) log.info('New article saving', { @@ -311,13 +313,6 @@ export const createArticleResolver = authorized< await makeStorageFilePublic(uploadFileData.id, uploadFileData.fileName) } - // save page's state and labels - libraryItemToSave.archivedAt = - state === ArticleSavingRequestStatus.Archived ? new Date() : null - if (inputLabels) { - libraryItemToSave.labels = await findOrCreateLabels(inputLabels, uid) - } - let libraryItemToReturn: LibraryItem const existingLibraryItem = await findLibraryItemByUrl( @@ -326,15 +321,15 @@ export const createArticleResolver = authorized< ) articleSavingRequestId = existingLibraryItem?.id || articleSavingRequestId if (articleSavingRequestId) { - // update existing page's state from processing to succeeded + // update existing item's state from processing to succeeded libraryItemToReturn = await updateLibraryItem( articleSavingRequestId, - libraryItemToSave, + libraryItemToSave as QueryDeepPartialEntity, uid, pubsub ) } else { - // create new page in database + // create new item in database libraryItemToReturn = await createLibraryItem( libraryItemToSave, uid, @@ -342,6 +337,12 @@ export const createArticleResolver = authorized< ) } + // save labels in item + if (inputLabels) { + const labels = await findOrCreateLabels(inputLabels, user.id) + await saveLabelsInLibraryItem(labels, libraryItemToReturn.id, user.id) + } + log.info( 'item created in database', libraryItemToReturn.id, @@ -524,7 +525,7 @@ export const setBookmarkArticleResolver = authorized< SetBookmarkArticleError, MutationSetBookmarkArticleArgs >(async (_, { input: { articleID } }, { uid, log, pubsub }) => { - // delete the page and its metadata + // delete the item and its metadata const deletedLibraryItem = await updateLibraryItem( articleID, { @@ -545,7 +546,7 @@ export const setBookmarkArticleResolver = authorized< }) log.info('Article unbookmarked', { - page: Object.assign({}, deletedLibraryItem, { + item: Object.assign({}, deletedLibraryItem, { readableContent: undefined, originalContent: undefined, }), @@ -601,7 +602,7 @@ export const saveArticleReadingProgressResolver = authorized< : undefined // If setting to zero we accept the update, otherwise we require it // be greater than the current reading progress. - const updatedPart: DeepPartial = { + const updatedPart: QueryDeepPartialEntity = { readingProgressBottomPercent: readingProgressPercent === 0 ? 0 @@ -834,7 +835,7 @@ export const setFavoriteArticleResolver = authorized< } const labels = await findOrCreateLabels([label], uid) - // adds Favorites label to page + // adds Favorites label to item await addLabelsToLibraryItem(labels, id, uid) return { diff --git a/packages/api/src/resolvers/upload_files/index.ts b/packages/api/src/resolvers/upload_files/index.ts index e94154b96..36169b5c4 100644 --- a/packages/api/src/resolvers/upload_files/index.ts +++ b/packages/api/src/resolvers/upload_files/index.ts @@ -125,15 +125,13 @@ export const uploadFileRequestResolver = authorized< let createdItemId: string | undefined = undefined if (input.createPageEntry) { // If we have a file:// URL, don't try to match it - // and create a copy of the page, just create a + // and create a copy of the item, just create a // new item. const item = await findLibraryItemByUrl(input.url, uid) if (item) { await updateLibraryItem( item.id, { - savedAt: new Date(), - archivedAt: null, state: LibraryItemState.Processing, }, uid diff --git a/packages/api/src/routers/page_router.ts b/packages/api/src/routers/page_router.ts index 990a49951..b03ae2099 100644 --- a/packages/api/src/routers/page_router.ts +++ b/packages/api/src/routers/page_router.ts @@ -16,7 +16,7 @@ import { createLibraryItem, findLibraryItemById, findLibraryItemByUrl, - updateLibraryItem, + restoreLibraryItem, } from '../services/library_item' import { addRecommendation } from '../services/recommendation' import { getTokenByRequest } from '../utils/auth' @@ -105,18 +105,8 @@ export function pageRouter() { const item = await findLibraryItemByUrl(url, claims.uid) if (item) { - logger.info('updating page') - await updateLibraryItem( - item.id, - { - savedAt: new Date(), - archivedAt: null, - state: LibraryItemState.Succeeded, - }, - claims.uid - ) + await restoreLibraryItem(item.id, claims.uid) } else { - logger.info('creating page') await createLibraryItem( { originalUrl: signedUrl, diff --git a/packages/api/src/routers/svc/content.ts b/packages/api/src/routers/svc/content.ts index 712ba7af1..fe0ba0af9 100644 --- a/packages/api/src/routers/svc/content.ts +++ b/packages/api/src/routers/svc/content.ts @@ -2,6 +2,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import express from 'express' +import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity' import { LibraryItem, LibraryItemState } from '../../entity/library_item' import { readPushSubscription } from '../../pubsub' import { authTrx } from '../../repository' @@ -81,7 +82,9 @@ export function contentServiceRouter() { return } - const itemToUpdate: Partial = { originalContent: msg.content } + const itemToUpdate: QueryDeepPartialEntity = { + originalContent: msg.content, + } if (msg.title) itemToUpdate.title = msg.title if (msg.author) itemToUpdate.author = msg.author if (msg.description) itemToUpdate.description = msg.description diff --git a/packages/api/src/services/create_page_save_request.ts b/packages/api/src/services/create_page_save_request.ts index 9c21144a6..a8720e3f3 100644 --- a/packages/api/src/services/create_page_save_request.ts +++ b/packages/api/src/services/create_page_save_request.ts @@ -113,7 +113,7 @@ export const createPageSaveRequest = async ({ if (!libraryItem) { logger.info('libraryItem does not exist', { url }) - // create processing page + // create processing item libraryItem = await createLibraryItem( { id: articleSavingRequestId, @@ -145,7 +145,7 @@ export const createPageSaveRequest = async ({ // get priority by checking rate limit if not specified priority = priority || (await getPriorityByRateLimit(userId)) - // enqueue task to parse page + // enqueue task to parse item await enqueueParseRequest({ url, userId, diff --git a/packages/api/src/services/library_item.ts b/packages/api/src/services/library_item.ts index 4c29188ed..ba2eba838 100644 --- a/packages/api/src/services/library_item.ts +++ b/packages/api/src/services/library_item.ts @@ -342,7 +342,7 @@ export const findLibraryItemByUrl = async ( ) } -export const refreshLibraryItem = async ( +export const restoreLibraryItem = async ( id: string, userId: string, pubsub = createPubSubClient() @@ -353,6 +353,7 @@ export const refreshLibraryItem = async ( state: LibraryItemState.Succeeded, savedAt: new Date(), archivedAt: null, + deletedAt: null, }, userId, pubsub @@ -361,17 +362,30 @@ export const refreshLibraryItem = async ( export const updateLibraryItem = async ( id: string, - libraryItem: DeepPartial, + libraryItem: QueryDeepPartialEntity, userId: string, pubsub = createPubSubClient() ): Promise => { const updatedLibraryItem = await authTrx( async (tx) => { const itemRepo = tx.withRepository(libraryItemRepository) - await itemRepo.update( - id, - libraryItem as QueryDeepPartialEntity - ) + + // reset deletedAt and archivedAt + switch (libraryItem.state) { + case LibraryItemState.Archived: + libraryItem.archivedAt = new Date() + break + case LibraryItemState.Deleted: + libraryItem.deletedAt = new Date() + break + case LibraryItemState.Processing: + case LibraryItemState.Succeeded: + libraryItem.archivedAt = null + libraryItem.deletedAt = null + break + } + + await itemRepo.update(id, libraryItem) return itemRepo.findOneByOrFail({ id }) }, @@ -379,7 +393,7 @@ export const updateLibraryItem = async ( userId ) - await pubsub.entityUpdated>( + await pubsub.entityUpdated>( EntityType.PAGE, { ...libraryItem, id }, userId diff --git a/packages/api/src/services/save_email.ts b/packages/api/src/services/save_email.ts index 433f6f148..17ce08f27 100644 --- a/packages/api/src/services/save_email.ts +++ b/packages/api/src/services/save_email.ts @@ -20,7 +20,7 @@ import { findOrCreateLabels, saveLabelsInLibraryItem } from './labels' import { createLibraryItem, findLibraryItemByUrl, - updateLibraryItem, + restoreLibraryItem, } from './library_item' import { updateReceivedEmail } from './received_emails' import { saveSubscription } from './subscriptions' @@ -72,12 +72,8 @@ export const saveEmail = async ( input.userId ) if (existingLibraryItem) { - const updatedLibraryItem = await updateLibraryItem( + const updatedLibraryItem = await restoreLibraryItem( existingLibraryItem.id, - { - archivedAt: null, - state: LibraryItemState.Succeeded, - }, input.userId ) logger.info('updated page from email', updatedLibraryItem) diff --git a/packages/api/src/services/save_file.ts b/packages/api/src/services/save_file.ts index 057b61ad0..f428cb77a 100644 --- a/packages/api/src/services/save_file.ts +++ b/packages/api/src/services/save_file.ts @@ -1,14 +1,9 @@ import { LibraryItemState } from '../entity/library_item' import { User } from '../entity/user' import { homePageURL } from '../env' -import { - ArticleSavingRequestStatus, - SaveErrorCode, - SaveFileInput, - SaveResult, -} from '../generated/graphql' +import { SaveErrorCode, SaveFileInput, SaveResult } from '../generated/graphql' import { getStorageFileDetails } from '../utils/uploads' -import { findOrCreateLabels } from './labels' +import { findOrCreateLabels, saveLabelsInLibraryItem } from './labels' import { updateLibraryItem } from './library_item' import { findUploadFileById, setFileUploadComplete } from './upload_file' @@ -34,24 +29,20 @@ export const saveFile = async ( } if (input.state || input.labels) { - // save state - const archivedAt = - input.state === ArticleSavingRequestStatus.Archived ? new Date() : null - // add labels to page - const labels = input.labels - ? await findOrCreateLabels(input.labels, user.id) - : undefined await updateLibraryItem( input.clientRequestId, { - archivedAt, - labels, state: input.state ? (input.state as unknown as LibraryItemState) : LibraryItemState.Succeeded, }, user.id ) + // add labels to item + if (input.labels) { + const labels = await findOrCreateLabels(input.labels, user.id) + await saveLabelsInLibraryItem(labels, input.clientRequestId, user.id) + } } return { diff --git a/packages/api/src/services/save_page.ts b/packages/api/src/services/save_page.ts index 3a4fadf7b..ad8d6d81c 100644 --- a/packages/api/src/services/save_page.ts +++ b/packages/api/src/services/save_page.ts @@ -1,5 +1,6 @@ import { Readability } from '@omnivore/readability' import { DeepPartial } from 'typeorm' +import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity' import { LibraryItem, LibraryItemState } from '../entity/library_item' import { User } from '../entity/user' import { homePageURL } from '../env' @@ -85,7 +86,7 @@ export const savePage = async ( itemType: parseResult.pageType, originalHtml: parseResult.domContent, canonicalUrl: parseResult.canonicalUrl, - saveTime: input.savedAt ? new Date(input.savedAt) : undefined, + saveTime: input.savedAt ? new Date(input.savedAt) : new Date(), publishedAt: input.publishedAt ? new Date(input.publishedAt) : undefined, state: input.state || undefined, rssFeedUrl: input.rssFeedUrl, @@ -109,11 +110,7 @@ export const savePage = async ( } } } else { - // save state - itemToSave.archivedAt = - input.state === ArticleSavingRequestStatus.Archived ? new Date() : null - - // check if the page already exists + // check if the item already exists const existingLibraryItem = await authTrx((t) => t.getRepository(LibraryItem).findOneBy({ user: { id: user.id }, @@ -121,7 +118,7 @@ export const savePage = async ( }) ) if (existingLibraryItem) { - // we don't want to update an rss feed page if rss-feeder is tring to re-save it + // we don't want to update an rss feed item if rss-feeder is tring to re-save it if (existingLibraryItem.subscription === input.rssFeedUrl) { return { clientRequestId, @@ -131,14 +128,18 @@ export const savePage = async ( clientRequestId = existingLibraryItem.id slug = existingLibraryItem.slug - await updateLibraryItem(clientRequestId, itemToSave, user.id) + await updateLibraryItem( + clientRequestId, + itemToSave as QueryDeepPartialEntity, + user.id + ) } else { - // do not publish a pubsub event if the page is imported + // do not publish a pubsub event if the item is imported const newItem = await createLibraryItem(itemToSave, user.id) clientRequestId = newItem.id } - // add labels to page + // save labels in item if (input.labels) { const labels = await findOrCreateLabels(input.labels, user.id) await saveLabelsInLibraryItem(labels, clientRequestId, user.id) diff --git a/packages/api/src/utils/helpers.ts b/packages/api/src/utils/helpers.ts index b723ba594..1e05cf77c 100644 --- a/packages/api/src/utils/helpers.ts +++ b/packages/api/src/utils/helpers.ts @@ -271,7 +271,7 @@ export const libraryItemToSearchItem = (item: LibraryItem): SearchItem => ({ export const isParsingTimeout = (libraryItem: LibraryItem): boolean => { return ( - // page processed more than 30 seconds ago + // item processed more than 30 seconds ago libraryItem.state === LibraryItemState.Processing && libraryItem.savedAt.getTime() < new Date().getTime() - 1000 * 30 )