fix: Required option not handled correctly for special fields (File, GeoPoint, Polygon) on GraphQL API mutations (#8915)
This commit is contained in:
@@ -964,7 +964,7 @@ describe('Auth Adapter features', () => {
|
|||||||
allowExpiredAuthDataToken: false,
|
allowExpiredAuthDataToken: false,
|
||||||
});
|
});
|
||||||
logger = require('../lib/logger').logger;
|
logger = require('../lib/logger').logger;
|
||||||
spyOn(logger, 'error').and.callFake(() => { });
|
spyOn(logger, 'error').and.callFake(() => {});
|
||||||
user = new Parse.User();
|
user = new Parse.User();
|
||||||
await user.save({ authData: { modernAdapter: { id: 'modernAdapter' } } });
|
await user.save({ authData: { modernAdapter: { id: 'modernAdapter' } } });
|
||||||
const user2 = new Parse.User();
|
const user2 = new Parse.User();
|
||||||
|
|||||||
@@ -9548,6 +9548,71 @@ describe('ParseGraphQLServer', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support files on required file', async () => {
|
||||||
|
try {
|
||||||
|
parseServer = await global.reconfigureServer({
|
||||||
|
publicServerURL: 'http://localhost:13377/parse',
|
||||||
|
});
|
||||||
|
const schemaController = await parseServer.config.databaseController.loadSchema();
|
||||||
|
await schemaController.addClassIfNotExists('SomeClassWithRequiredFile', {
|
||||||
|
someField: { type: 'File', required: true },
|
||||||
|
});
|
||||||
|
await resetGraphQLCache();
|
||||||
|
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
|
||||||
|
|
||||||
|
const body = new FormData();
|
||||||
|
body.append(
|
||||||
|
'operations',
|
||||||
|
JSON.stringify({
|
||||||
|
query: `
|
||||||
|
mutation CreateSomeObject(
|
||||||
|
$fields: CreateSomeClassWithRequiredFileFieldsInput
|
||||||
|
) {
|
||||||
|
createSomeClassWithRequiredFile(
|
||||||
|
input: { fields: $fields }
|
||||||
|
) {
|
||||||
|
someClassWithRequiredFile {
|
||||||
|
id
|
||||||
|
someField {
|
||||||
|
name
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: {
|
||||||
|
fields: {
|
||||||
|
someField: { upload: null },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
body.append('map', JSON.stringify({ 1: ['variables.fields.someField.upload'] }));
|
||||||
|
body.append('1', 'My File Content', {
|
||||||
|
filename: 'myFileName.txt',
|
||||||
|
contentType: 'text/plain',
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await fetch('http://localhost:13377/graphql', {
|
||||||
|
method: 'POST',
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
const resText = await res.text();
|
||||||
|
const result = JSON.parse(resText);
|
||||||
|
expect(
|
||||||
|
result.data.createSomeClassWithRequiredFile.someClassWithRequiredFile.someField.name
|
||||||
|
).toEqual(jasmine.stringMatching(/_myFileName.txt$/));
|
||||||
|
expect(
|
||||||
|
result.data.createSomeClassWithRequiredFile.someClassWithRequiredFile.someField.url
|
||||||
|
).toEqual(jasmine.stringMatching(/_myFileName.txt$/));
|
||||||
|
} catch (e) {
|
||||||
|
handleError(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should support file upload for on fly creation through pointer and relation', async () => {
|
it('should support file upload for on fly creation through pointer and relation', async () => {
|
||||||
parseServer = await global.reconfigureServer({
|
parseServer = await global.reconfigureServer({
|
||||||
publicServerURL: 'http://localhost:13377/parse',
|
publicServerURL: 'http://localhost:13377/parse',
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import Parse from 'parse/node';
|
import Parse from 'parse/node';
|
||||||
import { fromGlobalId } from 'graphql-relay';
|
import { fromGlobalId } from 'graphql-relay';
|
||||||
import { handleUpload } from '../loaders/filesMutations';
|
import { handleUpload } from '../loaders/filesMutations';
|
||||||
import * as defaultGraphQLTypes from '../loaders/defaultGraphQLTypes';
|
|
||||||
import * as objectsMutations from '../helpers/objectsMutations';
|
import * as objectsMutations from '../helpers/objectsMutations';
|
||||||
|
|
||||||
const transformTypes = async (
|
const transformTypes = async (
|
||||||
@@ -28,27 +27,28 @@ const transformTypes = async (
|
|||||||
inputTypeField = classGraphQLUpdateTypeFields[field];
|
inputTypeField = classGraphQLUpdateTypeFields[field];
|
||||||
}
|
}
|
||||||
if (inputTypeField) {
|
if (inputTypeField) {
|
||||||
switch (true) {
|
const parseFieldType = parseClass.fields[field].type;
|
||||||
case inputTypeField.type === defaultGraphQLTypes.GEO_POINT_INPUT:
|
switch (parseFieldType) {
|
||||||
|
case 'GeoPoint':
|
||||||
if (fields[field] === null) {
|
if (fields[field] === null) {
|
||||||
fields[field] = { __op: 'Delete' };
|
fields[field] = { __op: 'Delete' };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fields[field] = transformers.geoPoint(fields[field]);
|
fields[field] = transformers.geoPoint(fields[field]);
|
||||||
break;
|
break;
|
||||||
case inputTypeField.type === defaultGraphQLTypes.POLYGON_INPUT:
|
case 'Polygon':
|
||||||
if (fields[field] === null) {
|
if (fields[field] === null) {
|
||||||
fields[field] = { __op: 'Delete' };
|
fields[field] = { __op: 'Delete' };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fields[field] = transformers.polygon(fields[field]);
|
fields[field] = transformers.polygon(fields[field]);
|
||||||
break;
|
break;
|
||||||
case inputTypeField.type === defaultGraphQLTypes.FILE_INPUT:
|
case 'File':
|
||||||
// Use `originalFields` to handle file upload since fields are a deepcopy and do not
|
// We need to use the originalFields to handle the file upload
|
||||||
// keep the file object
|
// since fields are a deepcopy and do not keep the file object
|
||||||
fields[field] = await transformers.file(originalFields[field], req);
|
fields[field] = await transformers.file(originalFields[field], req);
|
||||||
break;
|
break;
|
||||||
case parseClass.fields[field].type === 'Relation':
|
case 'Relation':
|
||||||
fields[field] = await transformers.relation(
|
fields[field] = await transformers.relation(
|
||||||
parseClass.fields[field].targetClass,
|
parseClass.fields[field].targetClass,
|
||||||
field,
|
field,
|
||||||
@@ -58,7 +58,7 @@ const transformTypes = async (
|
|||||||
req
|
req
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case parseClass.fields[field].type === 'Pointer':
|
case 'Pointer':
|
||||||
if (fields[field] === null) {
|
if (fields[field] === null) {
|
||||||
fields[field] = { __op: 'Delete' };
|
fields[field] = { __op: 'Delete' };
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user