mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Simplify the API to create pages from PDFs
This creates a stub page when an upload is initiated, so the SaveFile (or create article from file) APIs do not need to be called. The PDF uploaded trigger fired by GCS will mark the upload as completed and update the page status.
This commit is contained in:
parent
4acb0f38f2
commit
e5bc68ca9e
3 changed files with 110 additions and 57 deletions
|
|
@ -5,6 +5,7 @@ import {
|
|||
MutationUploadFileRequestArgs,
|
||||
UploadFileStatus,
|
||||
UploadFileRequestErrorCode,
|
||||
ArticleSavingRequestStatus,
|
||||
} from '../../generated/graphql'
|
||||
import { WithDataSourcesContext } from '../types'
|
||||
import {
|
||||
|
|
@ -15,13 +16,17 @@ import path from 'path'
|
|||
import normalizeUrl from 'normalize-url'
|
||||
import { analytics } from '../../utils/analytics'
|
||||
import { env } from '../../env'
|
||||
import { createPage } from '../../elastic/pages'
|
||||
import { PageType } from '../../elastic/types'
|
||||
import { generateSlug } from '../../utils/helpers'
|
||||
|
||||
export const uploadFileRequestResolver: ResolverFn<
|
||||
UploadFileRequestResult,
|
||||
unknown,
|
||||
WithDataSourcesContext,
|
||||
MutationUploadFileRequestArgs
|
||||
> = async (_obj, { input }, { models, kx, claims }) => {
|
||||
> = async (_obj, { input }, ctx) => {
|
||||
const { models, kx, claims } = ctx
|
||||
let uploadFileData: { id: string | null } = {
|
||||
id: null,
|
||||
}
|
||||
|
|
@ -39,16 +44,19 @@ export const uploadFileRequestResolver: ResolverFn<
|
|||
},
|
||||
})
|
||||
|
||||
let title: string
|
||||
let fileName: string
|
||||
try {
|
||||
const url = normalizeUrl(new URL(input.url).href, {
|
||||
stripHash: true,
|
||||
stripWWW: false,
|
||||
})
|
||||
title = decodeURI(path.basename(new URL(url).pathname, '.pdf'))
|
||||
fileName = decodeURI(path.basename(new URL(url).pathname)).replace(
|
||||
/[^a-zA-Z0-9-_.]/g,
|
||||
''
|
||||
)
|
||||
|
||||
if (!fileName) {
|
||||
fileName = 'content.pdf'
|
||||
}
|
||||
|
|
@ -73,6 +81,31 @@ export const uploadFileRequestResolver: ResolverFn<
|
|||
uploadFilePathName,
|
||||
input.contentType
|
||||
)
|
||||
|
||||
const pageId = await createPage(
|
||||
{
|
||||
id: '',
|
||||
url: input.url,
|
||||
userId: claims.uid,
|
||||
title: title,
|
||||
hash: uploadFilePathName,
|
||||
content: '',
|
||||
pageType: PageType.File,
|
||||
uploadFileId: uploadFileData.id,
|
||||
slug: generateSlug(uploadFilePathName),
|
||||
createdAt: new Date(),
|
||||
savedAt: new Date(),
|
||||
readingProgressPercent: 0,
|
||||
readingProgressAnchorIndex: 0,
|
||||
state: ArticleSavingRequestStatus.Processing,
|
||||
},
|
||||
ctx
|
||||
)
|
||||
|
||||
if (!pageId) {
|
||||
return { errorCodes: [UploadFileRequestErrorCode.FailedCreate] }
|
||||
}
|
||||
|
||||
return { id: uploadFileData.id, uploadSignedUrl }
|
||||
} else {
|
||||
return { errorCodes: [UploadFileRequestErrorCode.FailedCreate] }
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ import {
|
|||
} from '../../datalayer/pubsub'
|
||||
import { Page } from '../../elastic/types'
|
||||
import { getPageByParam, updatePage } from '../../elastic/pages'
|
||||
import { ArticleSavingRequestStatus } from '../../generated/graphql'
|
||||
import { initModels } from '../../server'
|
||||
import { kx } from '../../datalayer/knex_config'
|
||||
import { setClaims } from '../../datalayer/helpers'
|
||||
|
||||
interface UpdateContentMessage {
|
||||
fileId: string
|
||||
|
|
@ -65,6 +69,22 @@ export function contentServiceRouter() {
|
|||
if (msg.author) pageToUpdate.author = msg.author
|
||||
if (msg.description) pageToUpdate.description = msg.description
|
||||
|
||||
// This event is fired after the file is fully uploaded,
|
||||
// so along with upadting content, we mark it as
|
||||
// succeeded.
|
||||
pageToUpdate.state = ArticleSavingRequestStatus.Succeeded
|
||||
|
||||
try {
|
||||
const models = initModels(kx, false)
|
||||
const uploadFileData = await kx.transaction(async (tx) => {
|
||||
await setClaims(tx, page.userId)
|
||||
return models.uploadFile.setFileUploadComplete(fileId, tx)
|
||||
})
|
||||
console.log('updated uploadFileData', uploadFileData)
|
||||
} catch (error) {
|
||||
console.log('error marking file upload as completed', error)
|
||||
}
|
||||
|
||||
const result = await updatePage(page.id, pageToUpdate, {
|
||||
pubsub: createPubSubClient(),
|
||||
uid: page.userId,
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ export const saveFile = async (
|
|||
): Promise<SaveResult> => {
|
||||
console.log('saving file with input', input)
|
||||
|
||||
/* We do not trust the values from client, lookup upload file by querying
|
||||
* with filtering on user ID and URL to verify client's uploadFileId is valid.
|
||||
*/
|
||||
// /* We do not trust the values from client, lookup upload file by querying
|
||||
// * with filtering on user ID and URL to verify client's uploadFileId is valid.
|
||||
// */
|
||||
const uploadFile = await ctx.models.uploadFile.getWhere({
|
||||
id: input.uploadFileId,
|
||||
userId: saver.id,
|
||||
|
|
@ -53,63 +53,63 @@ export const saveFile = async (
|
|||
return ctx.models.uploadFile.setFileUploadComplete(input.uploadFileId, tx)
|
||||
})
|
||||
|
||||
if (!uploadFileData || !uploadFileData.id || !uploadFileData.fileName) {
|
||||
console.log('error completing upload file request', input)
|
||||
return {
|
||||
errorCodes: [SaveErrorCode.Unknown],
|
||||
}
|
||||
}
|
||||
// if (!uploadFileData || !uploadFileData.id || !uploadFileData.fileName) {
|
||||
// console.log('error completing upload file request', input)
|
||||
// return {
|
||||
// errorCodes: [SaveErrorCode.Unknown],
|
||||
// }
|
||||
// }
|
||||
|
||||
const uploadFileUrlOverride = await makeStorageFilePublic(
|
||||
uploadFileData.id,
|
||||
uploadFileData.fileName
|
||||
)
|
||||
// // const uploadFileUrlOverride = await makeStorageFilePublic(
|
||||
// // uploadFileData.id,
|
||||
// // uploadFileData.fileName
|
||||
// // )
|
||||
|
||||
const matchedUserArticleRecord = await getPageByParam({
|
||||
userId: saver.id,
|
||||
url: uploadFileUrlOverride,
|
||||
state: ArticleSavingRequestStatus.Succeeded,
|
||||
})
|
||||
// const matchedUserArticleRecord = await getPageByParam({
|
||||
// userId: saver.id,
|
||||
// url: uploadFileData.url,
|
||||
// state: ArticleSavingRequestStatus.Succeeded,
|
||||
// })
|
||||
|
||||
if (matchedUserArticleRecord) {
|
||||
await updatePage(
|
||||
matchedUserArticleRecord.id,
|
||||
{
|
||||
savedAt: new Date(),
|
||||
archivedAt: null,
|
||||
},
|
||||
ctx
|
||||
)
|
||||
input.clientRequestId = matchedUserArticleRecord.id
|
||||
} else {
|
||||
const pageId = await createPage(
|
||||
{
|
||||
url: uploadFileUrlOverride,
|
||||
title: uploadFile.fileName,
|
||||
hash: uploadFileDetails.md5Hash,
|
||||
content: '',
|
||||
pageType: PageType.File,
|
||||
uploadFileId: input.uploadFileId,
|
||||
slug: generateSlug(uploadFile.fileName),
|
||||
userId: saver.id,
|
||||
id: input.clientRequestId,
|
||||
createdAt: new Date(),
|
||||
savedAt: new Date(),
|
||||
readingProgressPercent: 0,
|
||||
readingProgressAnchorIndex: 0,
|
||||
state: ArticleSavingRequestStatus.Succeeded,
|
||||
},
|
||||
ctx
|
||||
)
|
||||
// if (matchedUserArticleRecord) {
|
||||
// await updatePage(
|
||||
// matchedUserArticleRecord.id,
|
||||
// {
|
||||
// savedAt: new Date(),
|
||||
// archivedAt: null,
|
||||
// },
|
||||
// ctx
|
||||
// )
|
||||
// input.clientRequestId = matchedUserArticleRecord.id
|
||||
// } else {
|
||||
// const pageId = await createPage(
|
||||
// {
|
||||
// url: uploadFile.url,
|
||||
// title: uploadFile.fileName,
|
||||
// hash: uploadFileDetails.md5Hash,
|
||||
// content: '',
|
||||
// pageType: PageType.File,
|
||||
// uploadFileId: input.uploadFileId,
|
||||
// slug: generateSlug(uploadFile.fileName),
|
||||
// userId: saver.id,
|
||||
// id: input.clientRequestId,
|
||||
// createdAt: new Date(),
|
||||
// savedAt: new Date(),
|
||||
// readingProgressPercent: 0,
|
||||
// readingProgressAnchorIndex: 0,
|
||||
// state: ArticleSavingRequestStatus.Succeeded,
|
||||
// },
|
||||
// ctx
|
||||
// )
|
||||
|
||||
if (!pageId) {
|
||||
console.log('error creating page in elastic', input)
|
||||
return {
|
||||
errorCodes: [SaveErrorCode.Unknown],
|
||||
}
|
||||
}
|
||||
input.clientRequestId = pageId
|
||||
}
|
||||
// if (!pageId) {
|
||||
// console.log('error creating page in elastic', input)
|
||||
// return {
|
||||
// errorCodes: [SaveErrorCode.Unknown],
|
||||
// }
|
||||
// }
|
||||
// input.clientRequestId = pageId
|
||||
// }
|
||||
|
||||
return {
|
||||
clientRequestId: input.clientRequestId,
|
||||
|
|
|
|||
Loading…
Reference in a new issue