Skip to content

Commit 1aba638

Browse files
authored
fix: GraphQL file upload fails in case of use of pointer or relation (#8721)
1 parent 6f21195 commit 1aba638

File tree

4 files changed

+140
-8
lines changed

4 files changed

+140
-8
lines changed

Diff for: spec/ParseGraphQLServer.spec.js

+111-3
Original file line numberDiff line numberDiff line change
@@ -6832,7 +6832,7 @@ describe('ParseGraphQLServer', () => {
68326832

68336833
describe('Files Mutations', () => {
68346834
describe('Create', () => {
6835-
it_only_node_version('<17')('should return File object', async () => {
6835+
it('should return File object', async () => {
68366836
const clientMutationId = uuidv4();
68376837

68386838
parseServer = await global.reconfigureServer({
@@ -9298,7 +9298,7 @@ describe('ParseGraphQLServer', () => {
92989298
expect(result6[0].node.name).toEqual('imACountry3');
92999299
});
93009300

9301-
it_only_node_version('<17')('should support files', async () => {
9301+
it('should support files', async () => {
93029302
try {
93039303
parseServer = await global.reconfigureServer({
93049304
publicServerURL: 'http://localhost:13377/parse',
@@ -9546,7 +9546,115 @@ describe('ParseGraphQLServer', () => {
95469546
}
95479547
});
95489548

9549-
it_only_node_version('<17')('should not upload if file is too large', async () => {
9549+
it('should support file upload for on fly creation through pointer and relation', async () => {
9550+
parseServer = await global.reconfigureServer({
9551+
publicServerURL: 'http://localhost:13377/parse',
9552+
});
9553+
const schema = new Parse.Schema('SomeClass');
9554+
schema.addFile('someFileField');
9555+
schema.addPointer('somePointerField', 'SomeClass');
9556+
schema.addRelation('someRelationField', 'SomeClass');
9557+
await schema.save();
9558+
9559+
const body = new FormData();
9560+
body.append(
9561+
'operations',
9562+
JSON.stringify({
9563+
query: `
9564+
mutation UploadFiles(
9565+
$fields: CreateSomeClassFieldsInput
9566+
) {
9567+
createSomeClass(
9568+
input: { fields: $fields }
9569+
) {
9570+
someClass {
9571+
id
9572+
someFileField {
9573+
name
9574+
url
9575+
}
9576+
somePointerField {
9577+
id
9578+
someFileField {
9579+
name
9580+
url
9581+
}
9582+
}
9583+
someRelationField {
9584+
edges {
9585+
node {
9586+
id
9587+
someFileField {
9588+
name
9589+
url
9590+
}
9591+
}
9592+
}
9593+
}
9594+
}
9595+
}
9596+
}
9597+
`,
9598+
variables: {
9599+
fields: {
9600+
someFileField: { upload: null },
9601+
somePointerField: {
9602+
createAndLink: {
9603+
someFileField: { upload: null },
9604+
},
9605+
},
9606+
someRelationField: {
9607+
createAndAdd: [
9608+
{
9609+
someFileField: { upload: null },
9610+
},
9611+
],
9612+
},
9613+
},
9614+
},
9615+
})
9616+
);
9617+
body.append(
9618+
'map',
9619+
JSON.stringify({
9620+
1: ['variables.fields.someFileField.upload'],
9621+
2: ['variables.fields.somePointerField.createAndLink.someFileField.upload'],
9622+
3: ['variables.fields.someRelationField.createAndAdd.0.someFileField.upload'],
9623+
})
9624+
);
9625+
body.append('1', 'My File Content someFileField', {
9626+
filename: 'someFileField.txt',
9627+
contentType: 'text/plain',
9628+
});
9629+
body.append('2', 'My File Content somePointerField', {
9630+
filename: 'somePointerField.txt',
9631+
contentType: 'text/plain',
9632+
});
9633+
body.append('3', 'My File Content someRelationField', {
9634+
filename: 'someRelationField.txt',
9635+
contentType: 'text/plain',
9636+
});
9637+
9638+
const res = await fetch('http://localhost:13377/graphql', {
9639+
method: 'POST',
9640+
headers,
9641+
body,
9642+
});
9643+
expect(res.status).toEqual(200);
9644+
const result = await res.json();
9645+
console.log(result);
9646+
expect(result.data.createSomeClass.someClass.someFileField.name).toEqual(
9647+
jasmine.stringMatching(/_someFileField.txt$/)
9648+
);
9649+
expect(result.data.createSomeClass.someClass.somePointerField.someFileField.name).toEqual(
9650+
jasmine.stringMatching(/_somePointerField.txt$/)
9651+
);
9652+
expect(
9653+
result.data.createSomeClass.someClass.someRelationField.edges[0].node.someFileField.name
9654+
).toEqual(jasmine.stringMatching(/_someRelationField.txt$/));
9655+
});
9656+
9657+
it('should not upload if file is too large', async () => {
95509658
parseGraphQLServer.parseServer.config.maxUploadSize = '1kb';
95519659

95529660
const body = new FormData();

Diff for: src/GraphQL/loaders/parseClassMutations.js

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ const load = function (parseGraphQLSchema, parseClass, parseClassConfig: ?ParseG
8282
const parseFields = await transformTypes('create', fields, {
8383
className,
8484
parseGraphQLSchema,
85+
originalFields: args.fields,
8586
req: { config, auth, info },
8687
});
8788

@@ -190,6 +191,7 @@ const load = function (parseGraphQLSchema, parseClass, parseClassConfig: ?ParseG
190191
const parseFields = await transformTypes('update', fields, {
191192
className,
192193
parseGraphQLSchema,
194+
originalFields: args.fields,
193195
req: { config, auth, info },
194196
});
195197

Diff for: src/GraphQL/loaders/usersMutations.js

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const load = parseGraphQLSchema => {
3838
const parseFields = await transformTypes('create', fields, {
3939
className: '_User',
4040
parseGraphQLSchema,
41+
originalFields: args.fields,
4142
req: { config, auth, info },
4243
});
4344

@@ -114,6 +115,7 @@ const load = parseGraphQLSchema => {
114115
const parseFields = await transformTypes('create', fields, {
115116
className: '_User',
116117
parseGraphQLSchema,
118+
originalFields: args.fields,
117119
req: { config, auth, info },
118120
});
119121

Diff for: src/GraphQL/transformers/mutation.js

+25-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as objectsMutations from '../helpers/objectsMutations';
77
const transformTypes = async (
88
inputType: 'create' | 'update',
99
fields,
10-
{ className, parseGraphQLSchema, req }
10+
{ className, parseGraphQLSchema, req, originalFields }
1111
) => {
1212
const {
1313
classGraphQLCreateType,
@@ -44,13 +44,16 @@ const transformTypes = async (
4444
fields[field] = transformers.polygon(fields[field]);
4545
break;
4646
case inputTypeField.type === defaultGraphQLTypes.FILE_INPUT:
47-
fields[field] = await transformers.file(fields[field], req);
47+
// Use `originalFields` to handle file upload since fields are a deepcopy and do not
48+
// keep the file object
49+
fields[field] = await transformers.file(originalFields[field], req);
4850
break;
4951
case parseClass.fields[field].type === 'Relation':
5052
fields[field] = await transformers.relation(
5153
parseClass.fields[field].targetClass,
5254
field,
5355
fields[field],
56+
originalFields[field],
5457
parseGraphQLSchema,
5558
req
5659
);
@@ -64,6 +67,7 @@ const transformTypes = async (
6467
parseClass.fields[field].targetClass,
6568
field,
6669
fields[field],
70+
originalFields[field],
6771
parseGraphQLSchema,
6872
req
6973
);
@@ -135,7 +139,14 @@ const transformers = {
135139
}
136140
return parseACL;
137141
},
138-
relation: async (targetClass, field, value, parseGraphQLSchema, { config, auth, info }) => {
142+
relation: async (
143+
targetClass,
144+
field,
145+
value,
146+
originalValue,
147+
parseGraphQLSchema,
148+
{ config, auth, info }
149+
) => {
139150
if (Object.keys(value).length === 0)
140151
throw new Parse.Error(
141152
Parse.Error.INVALID_POINTER,
@@ -151,9 +162,10 @@ const transformers = {
151162
if (value.createAndAdd) {
152163
nestedObjectsToAdd = (
153164
await Promise.all(
154-
value.createAndAdd.map(async input => {
165+
value.createAndAdd.map(async (input, i) => {
155166
const parseFields = await transformTypes('create', input, {
156167
className: targetClass,
168+
originalFields: originalValue.createAndAdd[i],
157169
parseGraphQLSchema,
158170
req: { config, auth, info },
159171
});
@@ -204,7 +216,14 @@ const transformers = {
204216
}
205217
return op;
206218
},
207-
pointer: async (targetClass, field, value, parseGraphQLSchema, { config, auth, info }) => {
219+
pointer: async (
220+
targetClass,
221+
field,
222+
value,
223+
originalValue,
224+
parseGraphQLSchema,
225+
{ config, auth, info }
226+
) => {
208227
if (Object.keys(value).length > 1 || Object.keys(value).length === 0)
209228
throw new Parse.Error(
210229
Parse.Error.INVALID_POINTER,
@@ -216,6 +235,7 @@ const transformers = {
216235
const parseFields = await transformTypes('create', value.createAndLink, {
217236
className: targetClass,
218237
parseGraphQLSchema,
238+
originalFields: originalValue.createAndLink,
219239
req: { config, auth, info },
220240
});
221241
nestedObjectToAdd = await objectsMutations.createObject(

0 commit comments

Comments
 (0)