fix: GraphQL file upload fails in case of use of pointer or relation (#8721)
This commit is contained in:
@@ -6832,7 +6832,7 @@ describe('ParseGraphQLServer', () => {
|
||||
|
||||
describe('Files Mutations', () => {
|
||||
describe('Create', () => {
|
||||
it_only_node_version('<17')('should return File object', async () => {
|
||||
it('should return File object', async () => {
|
||||
const clientMutationId = uuidv4();
|
||||
|
||||
parseServer = await global.reconfigureServer({
|
||||
@@ -9298,7 +9298,7 @@ describe('ParseGraphQLServer', () => {
|
||||
expect(result6[0].node.name).toEqual('imACountry3');
|
||||
});
|
||||
|
||||
it_only_node_version('<17')('should support files', async () => {
|
||||
it('should support files', async () => {
|
||||
try {
|
||||
parseServer = await global.reconfigureServer({
|
||||
publicServerURL: 'http://localhost:13377/parse',
|
||||
@@ -9546,7 +9546,115 @@ describe('ParseGraphQLServer', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it_only_node_version('<17')('should not upload if file is too large', async () => {
|
||||
it('should support file upload for on fly creation through pointer and relation', async () => {
|
||||
parseServer = await global.reconfigureServer({
|
||||
publicServerURL: 'http://localhost:13377/parse',
|
||||
});
|
||||
const schema = new Parse.Schema('SomeClass');
|
||||
schema.addFile('someFileField');
|
||||
schema.addPointer('somePointerField', 'SomeClass');
|
||||
schema.addRelation('someRelationField', 'SomeClass');
|
||||
await schema.save();
|
||||
|
||||
const body = new FormData();
|
||||
body.append(
|
||||
'operations',
|
||||
JSON.stringify({
|
||||
query: `
|
||||
mutation UploadFiles(
|
||||
$fields: CreateSomeClassFieldsInput
|
||||
) {
|
||||
createSomeClass(
|
||||
input: { fields: $fields }
|
||||
) {
|
||||
someClass {
|
||||
id
|
||||
someFileField {
|
||||
name
|
||||
url
|
||||
}
|
||||
somePointerField {
|
||||
id
|
||||
someFileField {
|
||||
name
|
||||
url
|
||||
}
|
||||
}
|
||||
someRelationField {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
someFileField {
|
||||
name
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
fields: {
|
||||
someFileField: { upload: null },
|
||||
somePointerField: {
|
||||
createAndLink: {
|
||||
someFileField: { upload: null },
|
||||
},
|
||||
},
|
||||
someRelationField: {
|
||||
createAndAdd: [
|
||||
{
|
||||
someFileField: { upload: null },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
body.append(
|
||||
'map',
|
||||
JSON.stringify({
|
||||
1: ['variables.fields.someFileField.upload'],
|
||||
2: ['variables.fields.somePointerField.createAndLink.someFileField.upload'],
|
||||
3: ['variables.fields.someRelationField.createAndAdd.0.someFileField.upload'],
|
||||
})
|
||||
);
|
||||
body.append('1', 'My File Content someFileField', {
|
||||
filename: 'someFileField.txt',
|
||||
contentType: 'text/plain',
|
||||
});
|
||||
body.append('2', 'My File Content somePointerField', {
|
||||
filename: 'somePointerField.txt',
|
||||
contentType: 'text/plain',
|
||||
});
|
||||
body.append('3', 'My File Content someRelationField', {
|
||||
filename: 'someRelationField.txt',
|
||||
contentType: 'text/plain',
|
||||
});
|
||||
|
||||
const res = await fetch('http://localhost:13377/graphql', {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
expect(res.status).toEqual(200);
|
||||
const result = await res.json();
|
||||
console.log(result);
|
||||
expect(result.data.createSomeClass.someClass.someFileField.name).toEqual(
|
||||
jasmine.stringMatching(/_someFileField.txt$/)
|
||||
);
|
||||
expect(result.data.createSomeClass.someClass.somePointerField.someFileField.name).toEqual(
|
||||
jasmine.stringMatching(/_somePointerField.txt$/)
|
||||
);
|
||||
expect(
|
||||
result.data.createSomeClass.someClass.someRelationField.edges[0].node.someFileField.name
|
||||
).toEqual(jasmine.stringMatching(/_someRelationField.txt$/));
|
||||
});
|
||||
|
||||
it('should not upload if file is too large', async () => {
|
||||
parseGraphQLServer.parseServer.config.maxUploadSize = '1kb';
|
||||
|
||||
const body = new FormData();
|
||||
|
||||
@@ -82,6 +82,7 @@ const load = function (parseGraphQLSchema, parseClass, parseClassConfig: ?ParseG
|
||||
const parseFields = await transformTypes('create', fields, {
|
||||
className,
|
||||
parseGraphQLSchema,
|
||||
originalFields: args.fields,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
|
||||
@@ -190,6 +191,7 @@ const load = function (parseGraphQLSchema, parseClass, parseClassConfig: ?ParseG
|
||||
const parseFields = await transformTypes('update', fields, {
|
||||
className,
|
||||
parseGraphQLSchema,
|
||||
originalFields: args.fields,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ const load = parseGraphQLSchema => {
|
||||
const parseFields = await transformTypes('create', fields, {
|
||||
className: '_User',
|
||||
parseGraphQLSchema,
|
||||
originalFields: args.fields,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
|
||||
@@ -114,6 +115,7 @@ const load = parseGraphQLSchema => {
|
||||
const parseFields = await transformTypes('create', fields, {
|
||||
className: '_User',
|
||||
parseGraphQLSchema,
|
||||
originalFields: args.fields,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as objectsMutations from '../helpers/objectsMutations';
|
||||
const transformTypes = async (
|
||||
inputType: 'create' | 'update',
|
||||
fields,
|
||||
{ className, parseGraphQLSchema, req }
|
||||
{ className, parseGraphQLSchema, req, originalFields }
|
||||
) => {
|
||||
const {
|
||||
classGraphQLCreateType,
|
||||
@@ -44,13 +44,16 @@ const transformTypes = async (
|
||||
fields[field] = transformers.polygon(fields[field]);
|
||||
break;
|
||||
case inputTypeField.type === defaultGraphQLTypes.FILE_INPUT:
|
||||
fields[field] = await transformers.file(fields[field], req);
|
||||
// Use `originalFields` to handle file upload since fields are a deepcopy and do not
|
||||
// keep the file object
|
||||
fields[field] = await transformers.file(originalFields[field], req);
|
||||
break;
|
||||
case parseClass.fields[field].type === 'Relation':
|
||||
fields[field] = await transformers.relation(
|
||||
parseClass.fields[field].targetClass,
|
||||
field,
|
||||
fields[field],
|
||||
originalFields[field],
|
||||
parseGraphQLSchema,
|
||||
req
|
||||
);
|
||||
@@ -64,6 +67,7 @@ const transformTypes = async (
|
||||
parseClass.fields[field].targetClass,
|
||||
field,
|
||||
fields[field],
|
||||
originalFields[field],
|
||||
parseGraphQLSchema,
|
||||
req
|
||||
);
|
||||
@@ -135,7 +139,14 @@ const transformers = {
|
||||
}
|
||||
return parseACL;
|
||||
},
|
||||
relation: async (targetClass, field, value, parseGraphQLSchema, { config, auth, info }) => {
|
||||
relation: async (
|
||||
targetClass,
|
||||
field,
|
||||
value,
|
||||
originalValue,
|
||||
parseGraphQLSchema,
|
||||
{ config, auth, info }
|
||||
) => {
|
||||
if (Object.keys(value).length === 0)
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_POINTER,
|
||||
@@ -151,9 +162,10 @@ const transformers = {
|
||||
if (value.createAndAdd) {
|
||||
nestedObjectsToAdd = (
|
||||
await Promise.all(
|
||||
value.createAndAdd.map(async input => {
|
||||
value.createAndAdd.map(async (input, i) => {
|
||||
const parseFields = await transformTypes('create', input, {
|
||||
className: targetClass,
|
||||
originalFields: originalValue.createAndAdd[i],
|
||||
parseGraphQLSchema,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
@@ -204,7 +216,14 @@ const transformers = {
|
||||
}
|
||||
return op;
|
||||
},
|
||||
pointer: async (targetClass, field, value, parseGraphQLSchema, { config, auth, info }) => {
|
||||
pointer: async (
|
||||
targetClass,
|
||||
field,
|
||||
value,
|
||||
originalValue,
|
||||
parseGraphQLSchema,
|
||||
{ config, auth, info }
|
||||
) => {
|
||||
if (Object.keys(value).length > 1 || Object.keys(value).length === 0)
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_POINTER,
|
||||
@@ -216,6 +235,7 @@ const transformers = {
|
||||
const parseFields = await transformTypes('create', value.createAndLink, {
|
||||
className: targetClass,
|
||||
parseGraphQLSchema,
|
||||
originalFields: originalValue.createAndLink,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
nestedObjectToAdd = await objectsMutations.createObject(
|
||||
|
||||
Reference in New Issue
Block a user