Remove nested operations from GraphQL API (#5931)
* Remove nested operations * Improve error log * Fix bug schema to load * Fix ParseGraphQLSchema tests * Fix tests * Fix failing tests * Rename call to callCloudCode
This commit is contained in:
committed by
Antoine Cormouls
parent
47d1a74ac0
commit
ee5aeeaff5
@@ -211,7 +211,7 @@ describe('ParseGraphQLSchema', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('addGraphQLObjectQuery', () => {
|
||||
describe('addGraphQLQuery', () => {
|
||||
it('should not load and warn duplicated queries', async () => {
|
||||
let logged = false;
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
@@ -221,21 +221,19 @@ describe('ParseGraphQLSchema', () => {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Object query someClasses could not be added to the auto schema because it collided with an existing field.'
|
||||
'Query someClasses could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('someClasses', field)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLObjectsQueries['someClasses']).toBe(
|
||||
expect(parseGraphQLSchema.addGraphQLQuery('someClasses', field)).toBe(
|
||||
field
|
||||
);
|
||||
expect(parseGraphQLSchema.graphQLQueries['someClasses']).toBe(field);
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('someClasses', {})
|
||||
parseGraphQLSchema.addGraphQLQuery('someClasses', {})
|
||||
).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
@@ -252,16 +250,14 @@ describe('ParseGraphQLSchema', () => {
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('someClasses', field)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLObjectsQueries['someClasses']).toBe(
|
||||
expect(parseGraphQLSchema.addGraphQLQuery('someClasses', field)).toBe(
|
||||
field
|
||||
);
|
||||
expect(parseGraphQLSchema.graphQLQueries['someClasses']).toBe(field);
|
||||
expect(() =>
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('someClasses', {}, true)
|
||||
parseGraphQLSchema.addGraphQLQuery('someClasses', {}, true)
|
||||
).toThrowError(
|
||||
'Object query someClasses could not be added to the auto schema because it collided with an existing field.'
|
||||
'Query someClasses could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -274,15 +270,13 @@ describe('ParseGraphQLSchema', () => {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Object query get could not be added to the auto schema because it collided with an existing field.'
|
||||
'Query get could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('get', {})
|
||||
).toBeUndefined();
|
||||
expect(parseGraphQLSchema.addGraphQLQuery('get', {})).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
|
||||
@@ -297,16 +291,16 @@ describe('ParseGraphQLSchema', () => {
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
delete parseGraphQLSchema.graphQLObjectsQueries.get;
|
||||
delete parseGraphQLSchema.graphQLQueries.get;
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('get', field, true, true)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLObjectsQueries['get']).toBe(field);
|
||||
expect(parseGraphQLSchema.addGraphQLQuery('get', field, true, true)).toBe(
|
||||
field
|
||||
);
|
||||
expect(parseGraphQLSchema.graphQLQueries['get']).toBe(field);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addGraphQLObjectMutation', () => {
|
||||
describe('addGraphQLMutation', () => {
|
||||
it('should not load and warn duplicated mutations', async () => {
|
||||
let logged = false;
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
@@ -316,7 +310,7 @@ describe('ParseGraphQLSchema', () => {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Object mutation createSomeClass could not be added to the auto schema because it collided with an existing field.'
|
||||
'Mutation createSomeClass could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -324,13 +318,13 @@ describe('ParseGraphQLSchema', () => {
|
||||
await parseGraphQLSchema.load();
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', field)
|
||||
parseGraphQLSchema.addGraphQLMutation('createSomeClass', field)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLMutations['createSomeClass']).toBe(
|
||||
field
|
||||
);
|
||||
expect(
|
||||
parseGraphQLSchema.graphQLObjectsMutations['createSomeClass']
|
||||
).toBe(field);
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', {})
|
||||
parseGraphQLSchema.addGraphQLMutation('createSomeClass', {})
|
||||
).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
@@ -348,15 +342,15 @@ describe('ParseGraphQLSchema', () => {
|
||||
await parseGraphQLSchema.load();
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', field)
|
||||
).toBe(field);
|
||||
expect(
|
||||
parseGraphQLSchema.graphQLObjectsMutations['createSomeClass']
|
||||
parseGraphQLSchema.addGraphQLMutation('createSomeClass', field)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLMutations['createSomeClass']).toBe(
|
||||
field
|
||||
);
|
||||
expect(() =>
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', {}, true)
|
||||
parseGraphQLSchema.addGraphQLMutation('createSomeClass', {}, true)
|
||||
).toThrowError(
|
||||
'Object mutation createSomeClass could not be added to the auto schema because it collided with an existing field.'
|
||||
'Mutation createSomeClass could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -369,14 +363,14 @@ describe('ParseGraphQLSchema', () => {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Object mutation create could not be added to the auto schema because it collided with an existing field.'
|
||||
'Mutation create could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('create', {})
|
||||
parseGraphQLSchema.addGraphQLMutation('create', {})
|
||||
).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
@@ -392,12 +386,12 @@ describe('ParseGraphQLSchema', () => {
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
delete parseGraphQLSchema.graphQLObjectsMutations.create;
|
||||
delete parseGraphQLSchema.graphQLMutations.create;
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('create', field, true, true)
|
||||
parseGraphQLSchema.addGraphQLMutation('create', field, true, true)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLObjectsMutations['create']).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLMutations['create']).toBe(field);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -453,27 +447,27 @@ describe('ParseGraphQLSchema', () => {
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema1 = await parseGraphQLSchema.load();
|
||||
const types1 = parseGraphQLSchema.graphQLTypes;
|
||||
const objectQueries1 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations1 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
const queries1 = parseGraphQLSchema.graphQLQueries;
|
||||
const mutations1 = parseGraphQLSchema.graphQLMutations;
|
||||
const user = new Parse.Object('User');
|
||||
await user.save();
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema2 = await parseGraphQLSchema.load();
|
||||
const types2 = parseGraphQLSchema.graphQLTypes;
|
||||
const objectQueries2 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations2 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
const queries2 = parseGraphQLSchema.graphQLQueries;
|
||||
const mutations2 = parseGraphQLSchema.graphQLMutations;
|
||||
expect(schema1).not.toBe(schema2);
|
||||
expect(types1).not.toBe(types2);
|
||||
expect(types1.map(type => type.name).sort()).toEqual(
|
||||
types2.map(type => type.name).sort()
|
||||
);
|
||||
expect(objectQueries1).not.toBe(objectQueries2);
|
||||
expect(Object.keys(objectQueries1).sort()).toEqual(
|
||||
Object.keys(objectQueries2).sort()
|
||||
expect(queries1).not.toBe(queries2);
|
||||
expect(Object.keys(queries1).sort()).toEqual(
|
||||
Object.keys(queries2).sort()
|
||||
);
|
||||
expect(objectMutations1).not.toBe(objectMutations2);
|
||||
expect(Object.keys(objectMutations1).sort()).toEqual(
|
||||
Object.keys(objectMutations2).sort()
|
||||
expect(mutations1).not.toBe(mutations2);
|
||||
expect(Object.keys(mutations1).sort()).toEqual(
|
||||
Object.keys(mutations2).sort()
|
||||
);
|
||||
});
|
||||
|
||||
@@ -488,27 +482,27 @@ describe('ParseGraphQLSchema', () => {
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema1 = await parseGraphQLSchema.load();
|
||||
const types1 = parseGraphQLSchema.graphQLTypes;
|
||||
const objectQueries1 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations1 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
const queries1 = parseGraphQLSchema.graphQLQueries;
|
||||
const mutations1 = parseGraphQLSchema.graphQLMutations;
|
||||
const car2 = new Parse.Object('car');
|
||||
await car2.save();
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema2 = await parseGraphQLSchema.load();
|
||||
const types2 = parseGraphQLSchema.graphQLTypes;
|
||||
const objectQueries2 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations2 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
const queries2 = parseGraphQLSchema.graphQLQueries;
|
||||
const mutations2 = parseGraphQLSchema.graphQLMutations;
|
||||
expect(schema1).not.toBe(schema2);
|
||||
expect(types1).not.toBe(types2);
|
||||
expect(types1.map(type => type.name).sort()).toEqual(
|
||||
types2.map(type => type.name).sort()
|
||||
);
|
||||
expect(objectQueries1).not.toBe(objectQueries2);
|
||||
expect(Object.keys(objectQueries1).sort()).toEqual(
|
||||
Object.keys(objectQueries2).sort()
|
||||
expect(queries1).not.toBe(queries2);
|
||||
expect(Object.keys(queries1).sort()).toEqual(
|
||||
Object.keys(queries2).sort()
|
||||
);
|
||||
expect(objectMutations1).not.toBe(objectMutations2);
|
||||
expect(Object.keys(objectMutations1).sort()).toEqual(
|
||||
Object.keys(objectMutations2).sort()
|
||||
expect(mutations1).not.toBe(mutations2);
|
||||
expect(Object.keys(mutations1).sort()).toEqual(
|
||||
Object.keys(mutations2).sort()
|
||||
);
|
||||
});
|
||||
|
||||
@@ -522,25 +516,25 @@ describe('ParseGraphQLSchema', () => {
|
||||
await car.save();
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema1 = await parseGraphQLSchema.load();
|
||||
const objectQueries1 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations1 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
const queries1 = parseGraphQLSchema.graphQLQueries;
|
||||
const mutations1 = parseGraphQLSchema.graphQLMutations;
|
||||
const cars = new Parse.Object('cars');
|
||||
await cars.save();
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema2 = await parseGraphQLSchema.load();
|
||||
const objectQueries2 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations2 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
const queries2 = parseGraphQLSchema.graphQLQueries;
|
||||
const mutations2 = parseGraphQLSchema.graphQLMutations;
|
||||
expect(schema1).not.toBe(schema2);
|
||||
expect(objectQueries1).not.toBe(objectQueries2);
|
||||
expect(Object.keys(objectQueries1).sort()).toEqual(
|
||||
Object.keys(objectQueries2).sort()
|
||||
expect(queries1).not.toBe(queries2);
|
||||
expect(Object.keys(queries1).sort()).toEqual(
|
||||
Object.keys(queries2).sort()
|
||||
);
|
||||
expect(objectMutations1).not.toBe(objectMutations2);
|
||||
expect(mutations1).not.toBe(mutations2);
|
||||
expect(
|
||||
Object.keys(objectMutations1)
|
||||
Object.keys(mutations1)
|
||||
.concat('createCars', 'updateCars', 'deleteCars')
|
||||
.sort()
|
||||
).toEqual(Object.keys(objectMutations2).sort());
|
||||
).toEqual(Object.keys(mutations2).sort());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,18 +25,21 @@ const RESERVED_GRAPHQL_TYPE_NAMES = [
|
||||
'Query',
|
||||
'Mutation',
|
||||
'Subscription',
|
||||
'ObjectsQuery',
|
||||
'UsersQuery',
|
||||
'ObjectsMutation',
|
||||
'FilesMutation',
|
||||
'UsersMutation',
|
||||
'FunctionsMutation',
|
||||
'Viewer',
|
||||
'SignUpFieldsInput',
|
||||
'LogInFieldsInput',
|
||||
];
|
||||
const RESERVED_GRAPHQL_OBJECT_QUERY_NAMES = ['get', 'find'];
|
||||
const RESERVED_GRAPHQL_OBJECT_MUTATION_NAMES = ['create', 'update', 'delete'];
|
||||
const RESERVED_GRAPHQL_QUERY_NAMES = ['health', 'viewer', 'get', 'find'];
|
||||
const RESERVED_GRAPHQL_MUTATION_NAMES = [
|
||||
'signUp',
|
||||
'logIn',
|
||||
'logOut',
|
||||
'createFile',
|
||||
'callCloudCode',
|
||||
'create',
|
||||
'update',
|
||||
'delete',
|
||||
];
|
||||
|
||||
class ParseGraphQLSchema {
|
||||
databaseController: DatabaseController;
|
||||
@@ -87,9 +90,7 @@ class ParseGraphQLSchema {
|
||||
this.graphQLAutoSchema = null;
|
||||
this.graphQLSchema = null;
|
||||
this.graphQLTypes = [];
|
||||
this.graphQLObjectsQueries = {};
|
||||
this.graphQLQueries = {};
|
||||
this.graphQLObjectsMutations = {};
|
||||
this.graphQLMutations = {};
|
||||
this.graphQLSubscriptions = {};
|
||||
this.graphQLSchemaDirectivesDefinitions = null;
|
||||
@@ -104,6 +105,7 @@ class ParseGraphQLSchema {
|
||||
parseClassMutations.load(this, parseClass, parseClassConfig);
|
||||
}
|
||||
);
|
||||
|
||||
defaultGraphQLTypes.loadArrayResult(this, parseClasses);
|
||||
defaultGraphQLQueries.load(this);
|
||||
defaultGraphQLMutations.load(this);
|
||||
@@ -211,29 +213,28 @@ class ParseGraphQLSchema {
|
||||
return type;
|
||||
}
|
||||
|
||||
addGraphQLObjectQuery(
|
||||
addGraphQLQuery(
|
||||
fieldName,
|
||||
field,
|
||||
throwError = false,
|
||||
ignoreReserved = false
|
||||
) {
|
||||
if (
|
||||
(!ignoreReserved &&
|
||||
RESERVED_GRAPHQL_OBJECT_QUERY_NAMES.includes(fieldName)) ||
|
||||
this.graphQLObjectsQueries[fieldName]
|
||||
(!ignoreReserved && RESERVED_GRAPHQL_QUERY_NAMES.includes(fieldName)) ||
|
||||
this.graphQLQueries[fieldName]
|
||||
) {
|
||||
const message = `Object query ${fieldName} could not be added to the auto schema because it collided with an existing field.`;
|
||||
const message = `Query ${fieldName} could not be added to the auto schema because it collided with an existing field.`;
|
||||
if (throwError) {
|
||||
throw new Error(message);
|
||||
}
|
||||
this.log.warn(message);
|
||||
return undefined;
|
||||
}
|
||||
this.graphQLObjectsQueries[fieldName] = field;
|
||||
this.graphQLQueries[fieldName] = field;
|
||||
return field;
|
||||
}
|
||||
|
||||
addGraphQLObjectMutation(
|
||||
addGraphQLMutation(
|
||||
fieldName,
|
||||
field,
|
||||
throwError = false,
|
||||
@@ -241,17 +242,17 @@ class ParseGraphQLSchema {
|
||||
) {
|
||||
if (
|
||||
(!ignoreReserved &&
|
||||
RESERVED_GRAPHQL_OBJECT_MUTATION_NAMES.includes(fieldName)) ||
|
||||
this.graphQLObjectsMutations[fieldName]
|
||||
RESERVED_GRAPHQL_MUTATION_NAMES.includes(fieldName)) ||
|
||||
this.graphQLMutations[fieldName]
|
||||
) {
|
||||
const message = `Object mutation ${fieldName} could not be added to the auto schema because it collided with an existing field.`;
|
||||
const message = `Mutation ${fieldName} could not be added to the auto schema because it collided with an existing field.`;
|
||||
if (throwError) {
|
||||
throw new Error(message);
|
||||
}
|
||||
this.log.warn(message);
|
||||
return undefined;
|
||||
}
|
||||
this.graphQLObjectsMutations[fieldName] = field;
|
||||
this.graphQLMutations[fieldName] = field;
|
||||
return field;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,9 @@ class ParseGraphQLServer {
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
this.log.error(e);
|
||||
this.log.error(
|
||||
e.stack || (typeof e.toString === 'function' && e.toString()) || e
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,17 @@ import * as objectsQueries from './objectsQueries';
|
||||
import * as usersQueries from './usersQueries';
|
||||
|
||||
const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.graphQLQueries.health = {
|
||||
description:
|
||||
'The health query can be used to check if the server is up and running.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
resolve: () => true,
|
||||
};
|
||||
parseGraphQLSchema.addGraphQLQuery(
|
||||
'health',
|
||||
{
|
||||
description:
|
||||
'The health query can be used to check if the server is up and running.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
resolve: () => true,
|
||||
},
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
objectsQueries.load(parseGraphQLSchema);
|
||||
usersQueries.load(parseGraphQLSchema);
|
||||
|
||||
@@ -1,93 +1,83 @@
|
||||
import { GraphQLObjectType, GraphQLNonNull } from 'graphql';
|
||||
import { GraphQLNonNull } from 'graphql';
|
||||
import { GraphQLUpload } from 'graphql-upload';
|
||||
import Parse from 'parse/node';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
import logger from '../../logger';
|
||||
|
||||
const load = parseGraphQLSchema => {
|
||||
const fields = {};
|
||||
parseGraphQLSchema.addGraphQLMutation(
|
||||
'createFile',
|
||||
{
|
||||
description:
|
||||
'The create mutation can be used to create and upload a new file.',
|
||||
args: {
|
||||
upload: {
|
||||
description: 'This is the new file to be created and uploaded',
|
||||
type: new GraphQLNonNull(GraphQLUpload),
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.FILE_INFO),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { upload } = args;
|
||||
const { config } = context;
|
||||
|
||||
fields.create = {
|
||||
description:
|
||||
'The create mutation can be used to create and upload a new file.',
|
||||
args: {
|
||||
upload: {
|
||||
description: 'This is the new file to be created and uploaded',
|
||||
type: new GraphQLNonNull(GraphQLUpload),
|
||||
const { createReadStream, filename, mimetype } = await upload;
|
||||
let data = null;
|
||||
if (createReadStream) {
|
||||
const stream = createReadStream();
|
||||
data = await new Promise((resolve, reject) => {
|
||||
let data = '';
|
||||
stream
|
||||
.on('error', reject)
|
||||
.on('data', chunk => (data += chunk))
|
||||
.on('end', () => resolve(data));
|
||||
});
|
||||
}
|
||||
|
||||
if (!data || !data.length) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.FILE_SAVE_ERROR,
|
||||
'Invalid file upload.'
|
||||
);
|
||||
}
|
||||
|
||||
if (filename.length > 128) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_FILE_NAME,
|
||||
'Filename too long.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!filename.match(/^[_a-zA-Z0-9][a-zA-Z0-9@\.\ ~_-]*$/)) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_FILE_NAME,
|
||||
'Filename contains invalid characters.'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
return await config.filesController.createFile(
|
||||
config,
|
||||
filename,
|
||||
data,
|
||||
mimetype
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error('Error creating a file: ', e);
|
||||
throw new Parse.Error(
|
||||
Parse.Error.FILE_SAVE_ERROR,
|
||||
`Could not store file: ${filename}.`
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.FILE_INFO),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { upload } = args;
|
||||
const { config } = context;
|
||||
|
||||
const { createReadStream, filename, mimetype } = await upload;
|
||||
let data = null;
|
||||
if (createReadStream) {
|
||||
const stream = createReadStream();
|
||||
data = await new Promise((resolve, reject) => {
|
||||
let data = '';
|
||||
stream
|
||||
.on('error', reject)
|
||||
.on('data', chunk => (data += chunk))
|
||||
.on('end', () => resolve(data));
|
||||
});
|
||||
}
|
||||
|
||||
if (!data || !data.length) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.FILE_SAVE_ERROR,
|
||||
'Invalid file upload.'
|
||||
);
|
||||
}
|
||||
|
||||
if (filename.length > 128) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_FILE_NAME,
|
||||
'Filename too long.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!filename.match(/^[_a-zA-Z0-9][a-zA-Z0-9@\.\ ~_-]*$/)) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_FILE_NAME,
|
||||
'Filename contains invalid characters.'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
return await config.filesController.createFile(
|
||||
config,
|
||||
filename,
|
||||
data,
|
||||
mimetype
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error('Error creating a file: ', e);
|
||||
throw new Parse.Error(
|
||||
Parse.Error.FILE_SAVE_ERROR,
|
||||
`Could not store file: ${filename}.`
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const filesMutation = new GraphQLObjectType({
|
||||
name: 'FilesMutation',
|
||||
description: 'FilesMutation is the top level type for files mutations.',
|
||||
fields,
|
||||
});
|
||||
parseGraphQLSchema.addGraphQLType(filesMutation, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLMutations.files = {
|
||||
description: 'This is the top level for files mutations.',
|
||||
type: filesMutation,
|
||||
resolve: () => new Object(),
|
||||
};
|
||||
true,
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
export { load };
|
||||
|
||||
@@ -1,57 +1,46 @@
|
||||
import { GraphQLObjectType, GraphQLNonNull, GraphQLString } from 'graphql';
|
||||
import { GraphQLNonNull, GraphQLString } from 'graphql';
|
||||
import { FunctionsRouter } from '../../Routers/FunctionsRouter';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
|
||||
const load = parseGraphQLSchema => {
|
||||
const fields = {};
|
||||
|
||||
fields.call = {
|
||||
description:
|
||||
'The call mutation can be used to invoke a cloud code function.',
|
||||
args: {
|
||||
functionName: {
|
||||
description: 'This is the name of the function to be called.',
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
parseGraphQLSchema.addGraphQLMutation(
|
||||
'callCloudCode',
|
||||
{
|
||||
description:
|
||||
'The call mutation can be used to invoke a cloud code function.',
|
||||
args: {
|
||||
functionName: {
|
||||
description: 'This is the name of the function to be called.',
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
},
|
||||
params: {
|
||||
description: 'These are the params to be passed to the function.',
|
||||
type: defaultGraphQLTypes.OBJECT,
|
||||
},
|
||||
},
|
||||
params: {
|
||||
description: 'These are the params to be passed to the function.',
|
||||
type: defaultGraphQLTypes.OBJECT,
|
||||
type: defaultGraphQLTypes.ANY,
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { functionName, params } = args;
|
||||
const { config, auth, info } = context;
|
||||
|
||||
return (await FunctionsRouter.handleCloudFunction({
|
||||
params: {
|
||||
functionName,
|
||||
},
|
||||
config,
|
||||
auth,
|
||||
info,
|
||||
body: params,
|
||||
})).response.result;
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
type: defaultGraphQLTypes.ANY,
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { functionName, params } = args;
|
||||
const { config, auth, info } = context;
|
||||
|
||||
return (await FunctionsRouter.handleCloudFunction({
|
||||
params: {
|
||||
functionName,
|
||||
},
|
||||
config,
|
||||
auth,
|
||||
info,
|
||||
body: params,
|
||||
})).response.result;
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const functionsMutation = new GraphQLObjectType({
|
||||
name: 'FunctionsMutation',
|
||||
description:
|
||||
'FunctionsMutation is the top level type for functions mutations.',
|
||||
fields,
|
||||
});
|
||||
parseGraphQLSchema.addGraphQLType(functionsMutation, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLMutations.functions = {
|
||||
description: 'This is the top level for functions mutations.',
|
||||
type: functionsMutation,
|
||||
resolve: () => new Object(),
|
||||
};
|
||||
true,
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
export { load };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GraphQLNonNull, GraphQLBoolean, GraphQLObjectType } from 'graphql';
|
||||
import { GraphQLNonNull, GraphQLBoolean } from 'graphql';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
import rest from '../../rest';
|
||||
import { transformMutationInputToParse } from '../transformers/mutation';
|
||||
@@ -44,7 +44,7 @@ const deleteObject = async (className, objectId, config, auth, info) => {
|
||||
};
|
||||
|
||||
const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(
|
||||
parseGraphQLSchema.addGraphQLMutation(
|
||||
'create',
|
||||
{
|
||||
description:
|
||||
@@ -69,7 +69,7 @@ const load = parseGraphQLSchema => {
|
||||
true
|
||||
);
|
||||
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(
|
||||
parseGraphQLSchema.addGraphQLMutation(
|
||||
'update',
|
||||
{
|
||||
description:
|
||||
@@ -102,7 +102,7 @@ const load = parseGraphQLSchema => {
|
||||
true
|
||||
);
|
||||
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(
|
||||
parseGraphQLSchema.addGraphQLMutation(
|
||||
'delete',
|
||||
{
|
||||
description:
|
||||
@@ -126,19 +126,6 @@ const load = parseGraphQLSchema => {
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
const objectsMutation = new GraphQLObjectType({
|
||||
name: 'ObjectsMutation',
|
||||
description: 'ObjectsMutation is the top level type for objects mutations.',
|
||||
fields: parseGraphQLSchema.graphQLObjectsMutations,
|
||||
});
|
||||
parseGraphQLSchema.addGraphQLType(objectsMutation, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLMutations.objects = {
|
||||
description: 'This is the top level for objects mutations.',
|
||||
type: objectsMutation,
|
||||
resolve: () => new Object(),
|
||||
};
|
||||
};
|
||||
|
||||
export { createObject, updateObject, deleteObject, load };
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
GraphQLNonNull,
|
||||
GraphQLBoolean,
|
||||
GraphQLString,
|
||||
GraphQLObjectType,
|
||||
} from 'graphql';
|
||||
import { GraphQLNonNull, GraphQLBoolean, GraphQLString } from 'graphql';
|
||||
import getFieldNames from 'graphql-list-fields';
|
||||
import Parse from 'parse/node';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
@@ -134,7 +129,7 @@ const findObjects = async (
|
||||
};
|
||||
|
||||
const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.addGraphQLObjectQuery(
|
||||
parseGraphQLSchema.addGraphQLQuery(
|
||||
'get',
|
||||
{
|
||||
description:
|
||||
@@ -181,7 +176,7 @@ const load = parseGraphQLSchema => {
|
||||
true
|
||||
);
|
||||
|
||||
parseGraphQLSchema.addGraphQLObjectQuery(
|
||||
parseGraphQLSchema.addGraphQLQuery(
|
||||
'find',
|
||||
{
|
||||
description:
|
||||
@@ -252,19 +247,6 @@ const load = parseGraphQLSchema => {
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
const objectsQuery = new GraphQLObjectType({
|
||||
name: 'ObjectsQuery',
|
||||
description: 'ObjectsQuery is the top level type for objects queries.',
|
||||
fields: parseGraphQLSchema.graphQLObjectsQueries,
|
||||
});
|
||||
parseGraphQLSchema.addGraphQLType(objectsQuery, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLQueries.objects = {
|
||||
description: 'This is the top level for objects queries.',
|
||||
type: objectsQuery,
|
||||
resolve: () => new Object(),
|
||||
};
|
||||
};
|
||||
|
||||
export { getObject, findObjects, load };
|
||||
|
||||
@@ -94,7 +94,7 @@ const load = function(
|
||||
|
||||
if (isCreateEnabled) {
|
||||
const createGraphQLMutationName = `create${graphQLClassName}`;
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(createGraphQLMutationName, {
|
||||
parseGraphQLSchema.addGraphQLMutation(createGraphQLMutationName, {
|
||||
description: `The ${createGraphQLMutationName} mutation can be used to create a new object of the ${graphQLClassName} class.`,
|
||||
args: {
|
||||
fields: {
|
||||
@@ -155,7 +155,7 @@ const load = function(
|
||||
|
||||
if (isUpdateEnabled) {
|
||||
const updateGraphQLMutationName = `update${graphQLClassName}`;
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(updateGraphQLMutationName, {
|
||||
parseGraphQLSchema.addGraphQLMutation(updateGraphQLMutationName, {
|
||||
description: `The ${updateGraphQLMutationName} mutation can be used to update an object of the ${graphQLClassName} class.`,
|
||||
args: {
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
@@ -215,7 +215,7 @@ const load = function(
|
||||
|
||||
if (isDestroyEnabled) {
|
||||
const deleteGraphQLMutationName = `delete${graphQLClassName}`;
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(deleteGraphQLMutationName, {
|
||||
parseGraphQLSchema.addGraphQLMutation(deleteGraphQLMutationName, {
|
||||
description: `The ${deleteGraphQLMutationName} mutation can be used to delete an object of the ${graphQLClassName} class.`,
|
||||
args: {
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
|
||||
@@ -54,7 +54,7 @@ const load = function(
|
||||
if (isGetEnabled) {
|
||||
const getGraphQLQueryName =
|
||||
graphQLClassName.charAt(0).toLowerCase() + graphQLClassName.slice(1);
|
||||
parseGraphQLSchema.addGraphQLObjectQuery(getGraphQLQueryName, {
|
||||
parseGraphQLSchema.addGraphQLQuery(getGraphQLQueryName, {
|
||||
description: `The ${getGraphQLQueryName} query can be used to get an object of the ${graphQLClassName} class by its id.`,
|
||||
args: {
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
@@ -78,7 +78,7 @@ const load = function(
|
||||
const findGraphQLQueryName = pluralize(
|
||||
graphQLClassName.charAt(0).toLowerCase() + graphQLClassName.slice(1)
|
||||
);
|
||||
parseGraphQLSchema.addGraphQLObjectQuery(findGraphQLQueryName, {
|
||||
parseGraphQLSchema.addGraphQLQuery(findGraphQLQueryName, {
|
||||
description: `The ${findGraphQLQueryName} query can be used to find objects of the ${graphQLClassName} class.`,
|
||||
args: classGraphQLFindArgs,
|
||||
type: new GraphQLNonNull(
|
||||
|
||||
@@ -3,7 +3,6 @@ import { SchemaDirectiveVisitor } from 'graphql-tools';
|
||||
import { FunctionsRouter } from '../../Routers/FunctionsRouter';
|
||||
|
||||
export const definitions = gql`
|
||||
directive @namespace on FIELD_DEFINITION
|
||||
directive @resolve(to: String) on FIELD_DEFINITION
|
||||
directive @mock(with: Any!) on FIELD_DEFINITION
|
||||
`;
|
||||
@@ -11,14 +10,6 @@ export const definitions = gql`
|
||||
const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.graphQLSchemaDirectivesDefinitions = definitions;
|
||||
|
||||
class NamespaceDirectiveVisitor extends SchemaDirectiveVisitor {
|
||||
visitFieldDefinition(field) {
|
||||
field.resolve = () => ({});
|
||||
}
|
||||
}
|
||||
|
||||
parseGraphQLSchema.graphQLSchemaDirectives.namespace = NamespaceDirectiveVisitor;
|
||||
|
||||
class ResolveDirectiveVisitor extends SchemaDirectiveVisitor {
|
||||
visitFieldDefinition(field) {
|
||||
field.resolve = async (_source, args, context) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GraphQLNonNull, GraphQLObjectType } from 'graphql';
|
||||
import { GraphQLNonNull } from 'graphql';
|
||||
import UsersRouter from '../../Routers/UsersRouter';
|
||||
import * as objectsMutations from './objectsMutations';
|
||||
import { getUserFromSessionToken } from './usersQueries';
|
||||
@@ -9,110 +9,111 @@ const load = parseGraphQLSchema => {
|
||||
if (parseGraphQLSchema.isUsersClassDisabled) {
|
||||
return;
|
||||
}
|
||||
const fields = {};
|
||||
|
||||
fields.signUp = {
|
||||
description: 'The signUp mutation can be used to sign the user up.',
|
||||
args: {
|
||||
fields: {
|
||||
descriptions: 'These are the fields of the user.',
|
||||
type: parseGraphQLSchema.parseClassTypes['_User'].signUpInputType,
|
||||
parseGraphQLSchema.addGraphQLMutation(
|
||||
'signUp',
|
||||
{
|
||||
description: 'The signUp mutation can be used to sign the user up.',
|
||||
args: {
|
||||
fields: {
|
||||
descriptions: 'These are the fields of the user.',
|
||||
type: parseGraphQLSchema.parseClassTypes['_User'].signUpInputType,
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, args, context, mutationInfo) {
|
||||
try {
|
||||
const { fields } = args;
|
||||
|
||||
const { config, auth, info } = context;
|
||||
|
||||
const { sessionToken } = await objectsMutations.createObject(
|
||||
'_User',
|
||||
fields,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
);
|
||||
|
||||
info.sessionToken = sessionToken;
|
||||
|
||||
return await getUserFromSessionToken(config, info, mutationInfo);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, args, context, mutationInfo) {
|
||||
try {
|
||||
const { fields } = args;
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
const { config, auth, info } = context;
|
||||
parseGraphQLSchema.addGraphQLMutation(
|
||||
'logIn',
|
||||
{
|
||||
description: 'The logIn mutation can be used to log the user in.',
|
||||
args: {
|
||||
fields: {
|
||||
description: 'This is data needed to login',
|
||||
type: parseGraphQLSchema.parseClassTypes['_User'].logInInputType,
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const {
|
||||
fields: { username, password },
|
||||
} = args;
|
||||
const { config, auth, info } = context;
|
||||
|
||||
const { sessionToken } = await objectsMutations.createObject(
|
||||
'_User',
|
||||
fields,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
);
|
||||
|
||||
info.sessionToken = sessionToken;
|
||||
|
||||
return await getUserFromSessionToken(config, info, mutationInfo);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
fields.logIn = {
|
||||
description: 'The logIn mutation can be used to log the user in.',
|
||||
args: {
|
||||
fields: {
|
||||
description: 'This is data needed to login',
|
||||
type: parseGraphQLSchema.parseClassTypes['_User'].logInInputType,
|
||||
return (await usersRouter.handleLogIn({
|
||||
body: {
|
||||
username,
|
||||
password,
|
||||
},
|
||||
query: {},
|
||||
config,
|
||||
auth,
|
||||
info,
|
||||
})).response;
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const {
|
||||
fields: { username, password },
|
||||
} = args;
|
||||
const { config, auth, info } = context;
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
return (await usersRouter.handleLogIn({
|
||||
body: {
|
||||
username,
|
||||
password,
|
||||
},
|
||||
query: {},
|
||||
config,
|
||||
auth,
|
||||
info,
|
||||
})).response;
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
parseGraphQLSchema.addGraphQLMutation(
|
||||
'logOut',
|
||||
{
|
||||
description: 'The logOut mutation can be used to log the user out.',
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, _args, context, mutationInfo) {
|
||||
try {
|
||||
const { config, auth, info } = context;
|
||||
|
||||
const viewer = await getUserFromSessionToken(
|
||||
config,
|
||||
info,
|
||||
mutationInfo
|
||||
);
|
||||
|
||||
await usersRouter.handleLogOut({
|
||||
config,
|
||||
auth,
|
||||
info,
|
||||
});
|
||||
|
||||
return viewer;
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
fields.logOut = {
|
||||
description: 'The logOut mutation can be used to log the user out.',
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, _args, context, mutationInfo) {
|
||||
try {
|
||||
const { config, auth, info } = context;
|
||||
|
||||
const viewer = await getUserFromSessionToken(
|
||||
config,
|
||||
info,
|
||||
mutationInfo
|
||||
);
|
||||
|
||||
await usersRouter.handleLogOut({
|
||||
config,
|
||||
auth,
|
||||
info,
|
||||
});
|
||||
|
||||
return viewer;
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const usersMutation = new GraphQLObjectType({
|
||||
name: 'UsersMutation',
|
||||
description: 'UsersMutation is the top level type for files mutations.',
|
||||
fields,
|
||||
});
|
||||
parseGraphQLSchema.addGraphQLType(usersMutation, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLMutations.users = {
|
||||
description: 'This is the top level for users mutations.',
|
||||
type: usersMutation,
|
||||
resolve: () => new Object(),
|
||||
};
|
||||
true,
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
export { load };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GraphQLNonNull, GraphQLObjectType } from 'graphql';
|
||||
import { GraphQLNonNull } from 'graphql';
|
||||
import getFieldNames from 'graphql-list-fields';
|
||||
import Parse from 'parse/node';
|
||||
import rest from '../../rest';
|
||||
@@ -49,34 +49,25 @@ const load = parseGraphQLSchema => {
|
||||
if (parseGraphQLSchema.isUsersClassDisabled) {
|
||||
return;
|
||||
}
|
||||
const fields = {};
|
||||
|
||||
fields.viewer = {
|
||||
description:
|
||||
'The viewer query can be used to return the current user data.',
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, _args, context, queryInfo) {
|
||||
try {
|
||||
const { config, info } = context;
|
||||
return await getUserFromSessionToken(config, info, queryInfo);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
parseGraphQLSchema.addGraphQLQuery(
|
||||
'viewer',
|
||||
{
|
||||
description:
|
||||
'The viewer query can be used to return the current user data.',
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, _args, context, queryInfo) {
|
||||
try {
|
||||
const { config, info } = context;
|
||||
return await getUserFromSessionToken(config, info, queryInfo);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const usersQuery = new GraphQLObjectType({
|
||||
name: 'UsersQuery',
|
||||
description: 'UsersQuery is the top level type for users queries.',
|
||||
fields,
|
||||
});
|
||||
parseGraphQLSchema.addGraphQLType(usersQuery, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLQueries.users = {
|
||||
description: 'This is the top level for users queries.',
|
||||
type: usersQuery,
|
||||
resolve: () => new Object(),
|
||||
};
|
||||
true,
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
export { load, getUserFromSessionToken };
|
||||
|
||||
Reference in New Issue
Block a user