diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index ca9b026b5..3d3fd2765 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -80,12 +80,12 @@ import { isSiteBlockedForParse } from '../../utils/blocked' import { authorized, cleanUrl, + errorHandler, generateSlug, isBase64Image, isParsingTimeout, libraryItemToArticle, libraryItemToSearchItem, - pageError, titleForFilePath, userDataToUser, } from '../../utils/helpers' @@ -153,7 +153,7 @@ export const createArticleResolver = authorized< const userData = await userRepository.findById(uid) if (!userData) { - return pageError( + return errorHandler( { errorCodes: [CreateArticleErrorCode.Unauthorized], }, @@ -166,7 +166,7 @@ export const createArticleResolver = authorized< try { if (isSiteBlockedForParse(url)) { - return pageError( + return errorHandler( { errorCodes: [CreateArticleErrorCode.NotAllowedToParse], }, @@ -190,7 +190,6 @@ export const createArticleResolver = authorized< let title: string | undefined let parsedContent: Readability.ParseResult | null = null let canonicalUrl - let userArticleUrl: string | null = null let uploadFileHash = null let domContent = null let itemType = LibraryItemType.Unknown @@ -226,7 +225,7 @@ export const createArticleResolver = authorized< */ const uploadFile = await findUploadFileById(uploadFileId) if (!uploadFile) { - return pageError( + return errorHandler( { errorCodes: [CreateArticleErrorCode.UploadFileMissing] }, uid, articleSavingRequestId, @@ -238,7 +237,6 @@ export const createArticleResolver = authorized< uploadFile.fileName ) uploadFileHash = uploadFileDetails.md5Hash - userArticleUrl = uploadFileDetails.fileUrl canonicalUrl = uploadFile.url itemType = itemTypeForContentType(uploadFile.contentType) title = titleForFilePath(uploadFile.url) @@ -282,7 +280,6 @@ export const createArticleResolver = authorized< title, parsedContent, userId: uid, - itemId: articleSavingRequestId, slug, croppedPathname, originalHtml: domContent, @@ -295,21 +292,15 @@ export const createArticleResolver = authorized< log.info('New article saving', { parsedArticle: Object.assign({}, libraryItemToSave, { - content: undefined, - originalHtml: undefined, + readableContent: undefined, + originalContent: undefined, }), - userArticleUrl, - labels: { - source: 'resolver', - resolver: 'createArticleResolver', - userId: uid, - }, }) if (uploadFileId) { const uploadFileData = await setFileUploadComplete(uploadFileId) if (!uploadFileData || !uploadFileData.id || !uploadFileData.fileName) { - return pageError( + return errorHandler( { errorCodes: [CreateArticleErrorCode.UploadFileMissing], }, @@ -344,7 +335,7 @@ export const createArticleResolver = authorized< pubsub ) } else { - // create new page in elastic + // create new page in database libraryItemToReturn = await createLibraryItem( libraryItemToSave, uid, @@ -353,7 +344,7 @@ export const createArticleResolver = authorized< } log.info( - 'page created in elastic', + 'item created in database', libraryItemToReturn.id, libraryItemToReturn.originalUrl, libraryItemToReturn.slug, @@ -367,7 +358,7 @@ export const createArticleResolver = authorized< } } catch (error) { log.error('Error creating article', error) - return pageError( + return errorHandler( { errorCodes: [CreateArticleErrorCode.ElasticError], }, @@ -399,6 +390,7 @@ export const getArticleResolver = authorized< user: true, labels: true, }, + uploadFile: true, }, }) ) diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index eb6973c88..386da6a21 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -383,7 +383,7 @@ export const functionResolvers = { } return article.url }, - async originalArticleUrl(article: { url: string }) { + originalArticleUrl(article: { url: string }) { return article.url }, hasContent(article: { @@ -464,6 +464,9 @@ export const functionResolvers = { image(item: SearchItem) { return item.image && createImageProxyUrl(item.image, 320, 320) }, + originalArticleUrl(item: { url: string }) { + return item.url + }, }, Subscription: { newsletterEmail(subscription: Subscription) { diff --git a/packages/api/src/resolvers/upload_files/index.ts b/packages/api/src/resolvers/upload_files/index.ts index e399a933f..0a5001834 100644 --- a/packages/api/src/resolvers/upload_files/index.ts +++ b/packages/api/src/resolvers/upload_files/index.ts @@ -20,6 +20,7 @@ import { import { analytics } from '../../utils/analytics' import { authorized, generateSlug } from '../../utils/helpers' import { + contentReaderForLibraryItem, generateUploadFilePathName, generateUploadSignedUrl, getFilePublicUrl, @@ -127,25 +128,21 @@ export const uploadFileRequestResolver = authorized< // If we have a file:// URL, don't try to match it // and create a copy of the page, just create a // new item. - const item = isFileUrl(input.url) - ? await findLibraryItemByUrl(input.url, uid) - : undefined - + const item = await findLibraryItemByUrl(input.url, uid) if (item) { - if ( - !(await updateLibraryItem( - item.id, - { - savedAt: new Date(), - archivedAt: null, - }, - uid - )) - ) { - return { errorCodes: [UploadFileRequestErrorCode.FailedCreate] } - } + await updateLibraryItem( + item.id, + { + savedAt: new Date(), + archivedAt: null, + state: LibraryItemState.Processing, + }, + uid + ) createdItemId = item.id } else { + const itemType = itemTypeForContentType(input.contentType) + const uploadFileId = uploadFileData.id const item = await createLibraryItem( { originalUrl: isFileUrl(input.url) ? publicUrl : input.url, @@ -153,9 +150,11 @@ export const uploadFileRequestResolver = authorized< user: { id: uid }, title, readableContent: '', - itemType: itemTypeForContentType(input.contentType), + itemType, uploadFile: { id: uploadFileData.id }, slug: generateSlug(uploadFilePathName), + state: LibraryItemState.Processing, + contentReader: contentReaderForLibraryItem(itemType, uploadFileId), }, uid ) diff --git a/packages/api/src/services/create_page_save_request.ts b/packages/api/src/services/create_page_save_request.ts index c760d58d7..7fcf08696 100644 --- a/packages/api/src/services/create_page_save_request.ts +++ b/packages/api/src/services/create_page_save_request.ts @@ -81,7 +81,7 @@ export const createPageSaveRequest = async ({ userId, url, pubsub = createPubSubClient(), - articleSavingRequestId = uuidv4(), + articleSavingRequestId, state, priority, labels, @@ -149,7 +149,7 @@ export const createPageSaveRequest = async ({ await enqueueParseRequest({ url, userId, - saveRequestId: articleSavingRequestId, + saveRequestId: libraryItem.id, priority, state, labels, diff --git a/packages/api/src/services/save_file.ts b/packages/api/src/services/save_file.ts index 15063ca17..057b61ad0 100644 --- a/packages/api/src/services/save_file.ts +++ b/packages/api/src/services/save_file.ts @@ -1,3 +1,4 @@ +import { LibraryItemState } from '../entity/library_item' import { User } from '../entity/user' import { homePageURL } from '../env' import { @@ -6,7 +7,6 @@ import { SaveFileInput, SaveResult, } from '../generated/graphql' -import { logger } from '../utils/logger' import { getStorageFileDetails } from '../utils/uploads' import { findOrCreateLabels } from './labels' import { updateLibraryItem } from './library_item' @@ -16,8 +16,6 @@ export const saveFile = async ( input: SaveFileInput, user: User ): Promise => { - logger.info('saving file with input', input) - const pageId = input.clientRequestId const uploadFile = await findUploadFileById(input.uploadFileId) if (!uploadFile) { return { @@ -35,28 +33,25 @@ export const saveFile = async ( } } - // 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 if (input.state || input.labels) { - const updated = await updateLibraryItem( - pageId, + // 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 ) - if (!updated) { - logger.info('error updating page', pageId) - return { - errorCodes: [SaveErrorCode.Unknown], - } - } } return { diff --git a/packages/api/src/services/save_page.ts b/packages/api/src/services/save_page.ts index f64166121..daa718729 100644 --- a/packages/api/src/services/save_page.ts +++ b/packages/api/src/services/save_page.ts @@ -28,6 +28,7 @@ import { } from '../utils/helpers' import { logger } from '../utils/logger' import { parsePreparedContent } from '../utils/parser' +import { contentReaderForLibraryItem } from '../utils/uploads' import { createPageSaveRequest } from './create_page_save_request' import { createHighlight } from './highlights' import { findOrCreateLabels } from './labels' @@ -258,5 +259,6 @@ export const parsedContentToLibraryItem = ({ itemLanguage: parsedContent?.language, siteIcon: parsedContent?.siteIcon, wordCount: wordsCount(parsedContent?.textContent || ''), + contentReader: contentReaderForLibraryItem(itemType, uploadFileId), } } diff --git a/packages/api/src/services/upload_file.ts b/packages/api/src/services/upload_file.ts index 7b03e8544..863e457de 100644 --- a/packages/api/src/services/upload_file.ts +++ b/packages/api/src/services/upload_file.ts @@ -7,8 +7,12 @@ export const findUploadFileById = async (id: string) => { export const setFileUploadComplete = async (id: string, userId?: string) => { return authTrx( - async (tx) => - tx.getRepository(UploadFile).save({ id, status: 'COMPLETED' }), + async (tx) => { + const repo = tx.getRepository(UploadFile) + await repo.update(id, { status: 'COMPLETED' }) + + return repo.findOneByOrFail({ id }) + }, undefined, userId ) diff --git a/packages/api/src/utils/helpers.ts b/packages/api/src/utils/helpers.ts index fd03bd992..c27ccfb0a 100644 --- a/packages/api/src/utils/helpers.ts +++ b/packages/api/src/utils/helpers.ts @@ -178,7 +178,7 @@ export const generateSlug = (title: string): string => { export const MAX_CONTENT_LENGTH = 5e7 //50MB -export const pageError = async ( +export const errorHandler = async ( result: CreateArticleError, userId: string, pageId?: string | null, @@ -242,6 +242,8 @@ export const libraryItemToArticle = (item: LibraryItem): Article => ({ readingProgressAnchorIndex: item.readingProgressHighestReadAnchor, readingProgressPercent: item.readingProgressTopPercent, highlights: item.highlights?.map(highlightDataToHighlight) || [], + uploadFileId: item.uploadFile?.id, + pageType: item.itemType as unknown as PageType, }) export const libraryItemToSearchItem = (item: LibraryItem): SearchItem => ({ @@ -260,6 +262,7 @@ export const libraryItemToSearchItem = (item: LibraryItem): SearchItem => ({ ), image: item.thumbnail, highlights: item.highlights?.map(highlightDataToHighlight), + uploadFileId: item.uploadFile?.id, }) export const isParsingTimeout = (libraryItem: LibraryItem): boolean => { diff --git a/packages/api/src/utils/uploads.ts b/packages/api/src/utils/uploads.ts index 7ba3f4613..c625bb737 100644 --- a/packages/api/src/utils/uploads.ts +++ b/packages/api/src/utils/uploads.ts @@ -1,24 +1,24 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { File, GetSignedUrlConfig, Storage } from '@google-cloud/storage' +import { ContentReaderType, LibraryItemType } from '../entity/library_item' import { env } from '../env' -import { ContentReader, PageType } from '../generated/graphql' import { logger } from './logger' -export const contentReaderForPage = ( - pageType: PageType, +export const contentReaderForLibraryItem = ( + itemType: LibraryItemType, uploadFileId: string | null | undefined ) => { if (!uploadFileId) { - return ContentReader.Web + return ContentReaderType.WEB } - switch (pageType) { - case PageType.Book: - return ContentReader.Epub - case PageType.File: - return ContentReader.Pdf + switch (itemType) { + case LibraryItemType.Book: + return ContentReaderType.EPUB + case LibraryItemType.File: + return ContentReaderType.PDF default: - return ContentReader.Web + return ContentReaderType.WEB } } @@ -47,10 +47,6 @@ export const generateUploadSignedUrl = async ( contentType: string, selectedBucket?: string ): Promise => { - // if (env.dev.isLocal) { - // return 'http://localhost:3000/uploads/' + filePathName - // } - // These options will allow temporary uploading of file with requested content type const options: GetSignedUrlConfig = { version: 'v4',