[web] gracefully handle empty relativePath in uppy uploads (#36773)

GitOrigin-RevId: 640094f69cf53ba9f33a5bdc3b6d532547431d01
This commit is contained in:
Jakob Ackermann
2026-09-17 12:01:55 +00:00
committed by Copybot
parent c2cd5d686c
commit f62b8525f2
2 changed files with 58 additions and 3 deletions
@@ -29,7 +29,7 @@ const uploadProjectSchema = z.object({
body: z.strictObject({
name: z.string().nonempty(),
type: uploadMetaTypeSchema,
relativePath: zz.filepath().optional(),
relativePath: zz.filepath().or(z.literal('')).optional(),
}),
file: zz.uploadedFile(),
})
@@ -47,7 +47,7 @@ const uploadFileSchema = z.object({
// {success:false, error:'invalid_filename'} response instead of a
// generic validation error
name: z.string().optional(),
relativePath: zz.filepath().optional(),
relativePath: zz.filepath().or(z.literal('')).optional(),
type: uploadMetaTypeSchema,
targetFolderId: zz.objectId().optional(),
}),
@@ -63,7 +63,7 @@ const importDocumentSchema = z.object({
}),
body: z.strictObject({
name: z.string().nonempty(),
relativePath: zz.filepath().optional(),
relativePath: zz.filepath().or(z.literal('')).optional(),
type: uploadMetaTypeSchema,
}),
file: zz.uploadedFile(),
@@ -124,6 +124,29 @@ describe('ProjectStructureChanges', function () {
})
})
describe('uploading a project with relativePath set to the literal "" string', function () {
it('should create the project successfully', async function () {
const zipFilename = 'test_project_with_name.zip'
const zipFile = fs.createReadStream(
Path.resolve(Path.join(import.meta.dirname, '..', 'files', zipFilename))
)
const { response, body } = await owner.doRequest('POST', {
uri: 'project/new/upload',
formData: {
name: zipFilename,
qqfile: zipFile,
relativePath: '',
},
})
expect(response.statusCode).to.be.within(200, 299)
const parsedBody = JSON.parse(body)
expect(parsedBody.success).to.equal(true)
expect(parsedBody.project_id).to.be.a('string')
})
})
describe('uploading a project with a name', function () {
let exampleProjectId
const testProjectName = 'wombat'
@@ -199,6 +222,38 @@ describe('ProjectStructureChanges', function () {
error: 'invalid_upload_request',
})
})
it('should create file with relativePath set to literal ""', async function () {
const testTex = 'test.tex'
const stream = fs.createReadStream(
Path.resolve(Path.join(import.meta.dirname, '..', 'files', testTex))
)
const projectId = await owner.createProject('foo', {
template: 'blank',
})
const projectBefore = await ProjectGetter.promises.getProject(projectId)
const { response, body } = await owner.doRequest('POST', {
uri: `project/${projectId}/upload`,
qs: {
folder_id: projectBefore.rootFolder[0]._id.toString(),
},
formData: {
name: testTex,
qqfile: stream,
relativePath: '',
},
})
expect(response.statusCode).to.be.within(200, 299)
const parsedBody = JSON.parse(body)
expect(parsedBody.success).to.equal(true)
const project = await ProjectGetter.promises.getProject(projectId)
expect(project.rootFolder[0].docs.map(d => d.name)).to.deep.equal([
'main.tex',
testTex,
])
})
})
})