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'; import { transformTypes } from '../transformers/mutation'; const usersRouter = new UsersRouter(); const load = parseGraphQLSchema => { if (parseGraphQLSchema.isUsersClassDisabled) { return; } const signUpMutation = mutationWithClientMutationId({ name: 'SignUp', description: 'The signUp mutation can be used to create and sign up a new user.', inputFields: { fields: { descriptions: 'These are the fields of the new user to be created and signed up.', type: parseGraphQLSchema.parseClassTypes['_User'].classGraphQLCreateType, }, }, 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 } = args; const { config, auth, info } = context; const parseFields = await transformTypes('create', fields, { className: '_User', parseGraphQLSchema, req: { config, auth, info }, }); const { sessionToken, objectId } = await objectsMutations.createObject( '_User', parseFields, config, auth, info ); context.info.sessionToken = sessionToken; return { viewer: await getUserFromSessionToken( context, mutationInfo, 'viewer.user.', objectId ), }; } catch (e) { parseGraphQLSchema.handleError(e); } }, }); parseGraphQLSchema.addGraphQLType( signUpMutation.args.input.type.ofType, true, true ); 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 parseFields = await transformTypes('create', fields, { className: '_User', parseGraphQLSchema, req: { config, auth, info }, }); const { sessionToken, objectId } = await objectsMutations.createObject( '_User', { ...parseFields, authData }, config, auth, info ); context.info.sessionToken = sessionToken; return { viewer: await getUserFromSessionToken( context, mutationInfo, 'viewer.user.', objectId ), }; } 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', description: 'The logIn mutation can be used to log in an existing user.', inputFields: { username: { description: 'This is the username used to log in the user.', type: new GraphQLNonNull(GraphQLString), }, password: { description: 'This is the password used to log in the user.', type: new GraphQLNonNull(GraphQLString), }, }, outputFields: { viewer: { description: 'This is the existing user that was logged in and returned as a viewer.', type: new GraphQLNonNull(parseGraphQLSchema.viewerType), }, }, mutateAndGetPayload: async (args, context, mutationInfo) => { try { const { username, password } = args; const { config, auth, info } = context; const { sessionToken, objectId } = ( await usersRouter.handleLogIn({ body: { username, password, }, query: {}, config, auth, info, }) ).response; context.info.sessionToken = sessionToken; return { viewer: await getUserFromSessionToken( context, mutationInfo, 'viewer.user.', objectId ), }; } catch (e) { parseGraphQLSchema.handleError(e); } }, }); parseGraphQLSchema.addGraphQLType( logInMutation.args.input.type.ofType, true, true ); parseGraphQLSchema.addGraphQLType(logInMutation.type, true, true); parseGraphQLSchema.addGraphQLMutation('logIn', logInMutation, true, true); const logOutMutation = mutationWithClientMutationId({ name: 'LogOut', description: 'The logOut mutation can be used to log out an existing user.', outputFields: { viewer: { description: 'This is the existing user that was logged out and returned as a viewer.', type: new GraphQLNonNull(parseGraphQLSchema.viewerType), }, }, mutateAndGetPayload: async (_args, context, mutationInfo) => { try { const { config, auth, info } = context; const viewer = await getUserFromSessionToken( context, mutationInfo, 'viewer.user.', auth.user.id ); await usersRouter.handleLogOut({ config, auth, info, }); return { viewer }; } catch (e) { parseGraphQLSchema.handleError(e); } }, }); parseGraphQLSchema.addGraphQLType( logOutMutation.args.input.type.ofType, true, true ); parseGraphQLSchema.addGraphQLType(logOutMutation.type, true, true); parseGraphQLSchema.addGraphQLMutation('logOut', logOutMutation, true, true); const resetPasswordMutation = mutationWithClientMutationId({ name: 'ResetPassword', description: 'The resetPassword mutation can be used to reset the password of an existing user.', inputFields: { email: { descriptions: 'Email of the user that should receive the reset email', type: new GraphQLNonNull(GraphQLString), }, }, outputFields: { ok: { description: "It's always true.", type: new GraphQLNonNull(GraphQLBoolean), }, }, mutateAndGetPayload: async ({ email }, context) => { const { config, auth, info } = context; await usersRouter.handleResetRequest({ body: { email, }, config, auth, info, }); return { ok: true }; }, }); parseGraphQLSchema.addGraphQLType( resetPasswordMutation.args.input.type.ofType, true, true ); parseGraphQLSchema.addGraphQLType(resetPasswordMutation.type, true, true); parseGraphQLSchema.addGraphQLMutation( 'resetPassword', resetPasswordMutation, true, true ); const sendVerificationEmailMutation = mutationWithClientMutationId({ name: 'SendVerificationEmail', description: 'The sendVerificationEmail mutation can be used to send the verification email again.', inputFields: { email: { descriptions: 'Email of the user that should receive the verification email', type: new GraphQLNonNull(GraphQLString), }, }, outputFields: { ok: { description: "It's always true.", type: new GraphQLNonNull(GraphQLBoolean), }, }, mutateAndGetPayload: async ({ email }, context) => { try { const { config, auth, info } = context; await usersRouter.handleVerificationEmailRequest({ body: { email, }, config, auth, info, }); return { ok: true }; } catch (e) { parseGraphQLSchema.handleError(e); } }, }); parseGraphQLSchema.addGraphQLType( sendVerificationEmailMutation.args.input.type.ofType, true, true ); parseGraphQLSchema.addGraphQLType( sendVerificationEmailMutation.type, true, true ); parseGraphQLSchema.addGraphQLMutation( 'sendVerificationEmail', sendVerificationEmailMutation, true, true ); }; export { load };