diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 83c40b9fc4..4ad5249792 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -4,6 +4,7 @@ const req = require('../lib/request'); const fetch = require('node-fetch'); const FormData = require('form-data'); const ws = require('ws'); +require('./helper'); const pluralize = require('pluralize'); const { getMainDefinition } = require('apollo-utilities'); const { ApolloLink, split } = require('apollo-link'); @@ -907,7 +908,7 @@ describe('ParseGraphQLServer', () => { .map(field => field.name) .sort(); - expect(inputFields).toEqual(['clientMutationId', 'userFields']); + expect(inputFields).toEqual(['clientMutationId', 'fields']); }); it('should have clientMutationId in sign up mutation payload', async () => { @@ -7114,7 +7115,7 @@ describe('ParseGraphQLServer', () => { variables: { input: { clientMutationId, - userFields: { + fields: { username: 'user1', password: 'user1', someField: 'someValue', @@ -7129,6 +7130,63 @@ describe('ParseGraphQLServer', () => { expect(typeof result.data.signUp.viewer.sessionToken).toBe('string'); }); + it('should login with user', async () => { + const clientMutationId = uuidv4(); + const userSchema = new Parse.Schema('_User'); + parseServer = await global.reconfigureServer({ + publicServerURL: 'http://localhost:13377/parse', + auth: { + myAuth: { + module: global.mockCustomAuthenticator('parse', 'graphql'), + }, + }, + }); + + userSchema.addString('someField'); + await userSchema.update(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const result = await apolloClient.mutate({ + mutation: gql` + mutation LogInWith($input: LogInWithInput!) { + logInWith(input: $input) { + clientMutationId + viewer { + sessionToken + user { + someField + } + } + } + } + `, + variables: { + input: { + clientMutationId, + authData: { + myAuth: { + id: 'parse', + password: 'graphql', + }, + }, + fields: { + someField: 'someValue', + }, + }, + }, + }); + + expect(result.data.logInWith.clientMutationId).toEqual( + clientMutationId + ); + expect(result.data.logInWith.viewer.sessionToken).toBeDefined(); + expect(result.data.logInWith.viewer.user.someField).toEqual( + 'someValue' + ); + expect(typeof result.data.logInWith.viewer.sessionToken).toBe( + 'string' + ); + }); + it('should log the user in', async () => { const clientMutationId = uuidv4(); const user = new Parse.User(); diff --git a/src/GraphQL/loaders/usersMutations.js b/src/GraphQL/loaders/usersMutations.js index a25db157e1..701929677e 100644 --- a/src/GraphQL/loaders/usersMutations.js +++ b/src/GraphQL/loaders/usersMutations.js @@ -1,7 +1,13 @@ -import { GraphQLNonNull, GraphQLString, GraphQLBoolean } from 'graphql'; +import { + GraphQLNonNull, + GraphQLString, + GraphQLBoolean, + GraphQLInputObjectType, +} from 'graphql'; import { mutationWithClientMutationId } from 'graphql-relay'; import UsersRouter from '../../Routers/UsersRouter'; import * as objectsMutations from '../helpers/objectsMutations'; +import { OBJECT } from './defaultGraphQLTypes'; import { getUserFromSessionToken } from './usersQueries'; const usersRouter = new UsersRouter(); @@ -16,7 +22,7 @@ const load = parseGraphQLSchema => { description: 'The signUp mutation can be used to create and sign up a new user.', inputFields: { - userFields: { + fields: { descriptions: 'These are the fields of the new user to be created and signed up.', type: @@ -32,12 +38,12 @@ const load = parseGraphQLSchema => { }, mutateAndGetPayload: async (args, context, mutationInfo) => { try { - const { userFields } = args; + const { fields } = args; const { config, auth, info } = context; const { sessionToken } = await objectsMutations.createObject( '_User', - userFields, + fields, config, auth, info @@ -67,6 +73,90 @@ const load = parseGraphQLSchema => { ); parseGraphQLSchema.addGraphQLType(signUpMutation.type, true, true); parseGraphQLSchema.addGraphQLMutation('signUp', signUpMutation, true, true); + const logInWithMutation = mutationWithClientMutationId({ + name: 'LogInWith', + description: + 'The logInWith mutation can be used to signup, login user with 3rd party authentication system. This mutation create a user if the authData do not correspond to an existing one.', + inputFields: { + authData: { + descriptions: 'This is the auth data of your custom auth provider', + type: new GraphQLNonNull(OBJECT), + }, + fields: { + descriptions: + 'These are the fields of the user to be created/updated and logged in.', + type: new GraphQLInputObjectType({ + name: 'UserLoginWithInput', + fields: () => { + const classGraphQLCreateFields = parseGraphQLSchema.parseClassTypes[ + '_User' + ].classGraphQLCreateType.getFields(); + return Object.keys(classGraphQLCreateFields).reduce( + (fields, fieldName) => { + if ( + fieldName !== 'password' && + fieldName !== 'username' && + fieldName !== 'authData' + ) { + fields[fieldName] = classGraphQLCreateFields[fieldName]; + } + return fields; + }, + {} + ); + }, + }), + }, + }, + outputFields: { + viewer: { + description: + 'This is the new user that was created, signed up and returned as a viewer.', + type: new GraphQLNonNull(parseGraphQLSchema.viewerType), + }, + }, + mutateAndGetPayload: async (args, context, mutationInfo) => { + try { + const { fields, authData } = args; + const { config, auth, info } = context; + + const { sessionToken } = await objectsMutations.createObject( + '_User', + { ...fields, authData }, + config, + auth, + info + ); + + info.sessionToken = sessionToken; + + return { + viewer: await getUserFromSessionToken( + config, + info, + mutationInfo, + 'viewer.user.', + true + ), + }; + } catch (e) { + parseGraphQLSchema.handleError(e); + } + }, + }); + + parseGraphQLSchema.addGraphQLType( + logInWithMutation.args.input.type.ofType, + true, + true + ); + parseGraphQLSchema.addGraphQLType(logInWithMutation.type, true, true); + parseGraphQLSchema.addGraphQLMutation( + 'logInWith', + logInWithMutation, + true, + true + ); const logInMutation = mutationWithClientMutationId({ name: 'LogIn',