Merge pull request #778 from omnivore-app/fix/upload-request-file-urls

fix/upload request file urls
This commit is contained in:
Jackson Harper 2022-06-09 12:59:10 -07:00 committed by GitHub
commit eb3e78d756
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 151 additions and 6 deletions

View file

@ -46,7 +46,7 @@ export const createKeys = exclude(keys, defaultedKeys)
export type CreateSet = PickTuple<UploadFileData, typeof createKeys> &
Partialize<DefaultedSet>
export const updateKeys = ['status'] as const
export const updateKeys = ['url', 'status'] as const
export type UpdateSet = PickTuple<UploadFileData, typeof updateKeys>

View file

@ -11,6 +11,7 @@ import { WithDataSourcesContext } from '../types'
import {
generateUploadSignedUrl,
generateUploadFilePathName,
getFilePublicUrl,
} from '../../utils/uploads'
import path from 'path'
import normalizeUrl from 'normalize-url'
@ -19,6 +20,12 @@ import { env } from '../../env'
import { createPage, getPageByParam, updatePage } from '../../elastic/pages'
import { PageType } from '../../elastic/types'
import { generateSlug } from '../../utils/helpers'
import { validateUrl } from '../../services/create_page_save_request'
const isFileUrl = (url: string): boolean => {
const parsedUrl = new URL(url)
return parsedUrl.protocol == 'file:'
}
export const uploadFileRequestResolver: ResolverFn<
UploadFileRequestResult,
@ -60,6 +67,17 @@ export const uploadFileRequestResolver: ResolverFn<
if (!fileName) {
fileName = 'content.pdf'
}
if (!isFileUrl(url)) {
try {
validateUrl(url)
} catch (error) {
console.log('illegal file input url', error)
return {
errorCodes: [UploadFileRequestErrorCode.BadInput],
}
}
}
} catch {
return { errorCodes: [UploadFileRequestErrorCode.BadInput] }
}
@ -82,12 +100,28 @@ export const uploadFileRequestResolver: ResolverFn<
input.contentType
)
const publicUrl = getFilePublicUrl(uploadFilePathName)
// If this is a file URL, we swap in the GCS public URL
if (isFileUrl(input.url)) {
await models.uploadFile.update(uploadFileData.id, {
url: publicUrl,
status: UploadFileStatus.Initialized,
})
}
let createdPageId: string | undefined = undefined
if (input.createPageEntry) {
const page = await getPageByParam({
userId: claims.uid,
url: input.url,
})
// 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 page = isFileUrl(input.url)
? await getPageByParam({
userId: claims.uid,
url: input.url,
})
: undefined
if (page) {
if (
!(await updatePage(
@ -105,7 +139,7 @@ export const uploadFileRequestResolver: ResolverFn<
} else {
const pageId = await createPage(
{
url: input.url,
url: isFileUrl(input.url) ? publicUrl : input.url,
id: input.clientRequestId || '',
userId: claims.uid,
title: title,

View file

@ -15,6 +15,10 @@ const storage = env.fileUpload?.gcsUploadSAKeyFilePath
: new Storage()
const bucketName = env.fileUpload.gcsUploadBucket
export const getFilePublicUrl = (filePathName: string): string => {
return storage.bucket(bucketName).file(filePathName).publicUrl()
}
export const generateUploadSignedUrl = async (
filePathName: string,
contentType: string,

View file

@ -0,0 +1,107 @@
import { createTestUser, deleteTestUser } from '../db'
import {
generateFakeUuid,
graphqlRequest,
request,
} from '../util'
import * as chai from 'chai'
import { expect } from 'chai'
import 'mocha'
import { User } from '../../src/entity/user'
import chaiString from 'chai-string'
import {
PageContext,
} from '../../src/elastic/types'
import { createPubSubClient } from '../../src/datalayer/pubsub'
import {
deletePage,
getPageById,
} from '../../src/elastic/pages'
chai.use(chaiString)
// INPUT
// clientRequestId?: InputMaybe<Scalars['String']>;
// contentType: Scalars['String'];
// createPageEntry?: InputMaybe<Scalars['Boolean']>;
// url: Scalars['String'];
const uploadFileRequest = async (
authToken: string,
inputUrl: string,
clientRequestId: string,
createPageEntry = true
) => {
const query = `
mutation {
uploadFileRequest(
input: {
contentType: "application/pdf",
clientRequestId: "${clientRequestId}",
createPageEntry: ${createPageEntry},
url: "${inputUrl}"
}
) {
... on ArchiveLinkSuccess {
linkId
}
... on ArchiveLinkError {
errorCodes
}
}
}
`
return graphqlRequest(query, authToken).expect(200)
}
describe('uploadFileRequest API', () => {
const username = 'fakeUser'
let authToken: string
let user: User
let ctx: PageContext
before(async () => {
// create test user and login
user = await createTestUser(username)
const res = await request
.post('/local/debug/fake-user-login')
.send({ fakeEmail: user.email })
authToken = res.body.authToken
ctx = {
pubsub: createPubSubClient(),
refresh: true,
uid: user.id,
}
})
after(async () => {
await deleteTestUser(username)
})
describe('UploadFileRequest', () => {
context('when create article is true', () => {
const clientRequestId = generateFakeUuid()
after(async () => {
await deletePage(clientRequestId, ctx)
})
it('should create an article if create article is true', async () => {
const res = await uploadFileRequest(authToken, 'https://www.google.com', clientRequestId, true)
expect(res.body.data.uploadFileRequest.createdPageId).to.eql(clientRequestId)
const page = await getPageById(clientRequestId)
expect(page).to.be
})
it('should not save a file:// URL', async () => {
const res = await uploadFileRequest(authToken, 'file://foo.bar', clientRequestId, true)
expect(res.body.data.uploadFileRequest.createdPageId).to.eql(clientRequestId)
const page = await getPageById(clientRequestId)
expect(page?.url).to.startWith("https://")
})
})
})
})