Skip to content

Commit

Permalink
GraphQL: reset password with emailed token (parse-community#7290)
Browse files Browse the repository at this point in the history
* renamed "resetPassword" to "requestResetPassword" & created new "resetPassword" mutation

* added new route to handle resetPassword in UsersRouter.js

* updated resetPassword test to "requestResetPassword" mutation

* updated "resetPassword" mutation args description

* changed token arg description to rerun the tests

* directly using updatePassword for resetPassword

* removed handleResetPassword from UsersRouter.js file

* added test case for reset Password

* changed mutation names to "resetPassword" & "confirmResetPassword"

* changed mutation names in test also
  • Loading branch information
sadakchap authored and Arul- committed Mar 29, 2021
1 parent 011c045 commit a3a00d4
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 0 deletions.
71 changes: 71 additions & 0 deletions spec/ParseGraphQLServer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7086,6 +7086,77 @@ describe('ParseGraphQLServer', () => {
expect(result.data.resetPassword.clientMutationId).toEqual(clientMutationId);
expect(result.data.resetPassword.ok).toBeTruthy();
});

it('should reset password', async () => {
const clientMutationId = uuidv4();
let resetPasswordToken;
const emailAdapter = {
sendVerificationEmail: () => {},
sendPasswordResetEmail: ({ link }) => {
resetPasswordToken = link.split('token=')[1].split('&')[0];
},
sendMail: () => {},
};
parseServer = await global.reconfigureServer({
appName: 'test',
emailAdapter: emailAdapter,
publicServerURL: 'http://localhost:13377/parse',
auth: {
myAuth: {
module: global.mockCustomAuthenticator('parse', 'graphql'),
},
},
});
const user = new Parse.User();
user.setUsername('user1');
user.setPassword('user1');
user.setEmail('user1@user1.user1');
await user.signUp();
await Parse.User.logOut();
await Parse.User.requestPasswordReset('user1@user1.user1');
await apolloClient.mutate({
mutation: gql`
mutation ConfirmResetPassword($input: ConfirmResetPasswordInput!) {
confirmResetPassword(input: $input) {
clientMutationId
ok
}
}
`,
variables: {
input: {
clientMutationId,
username: 'user1',
password: 'newPassword',
token: resetPasswordToken,
},
},
});
const result = await apolloClient.mutate({
mutation: gql`
mutation LogInUser($input: LogInInput!) {
logIn(input: $input) {
clientMutationId
viewer {
sessionToken
}
}
}
`,
variables: {
input: {
clientMutationId,
username: 'user1',
password: 'newPassword',
},
},
});

expect(result.data.logIn.clientMutationId).toEqual(clientMutationId);
expect(result.data.logIn.viewer.sessionToken).toBeDefined();
expect(typeof result.data.logIn.viewer.sessionToken).toBe('string');
});

it('should send verification email again', async () => {
const clientMutationId = uuidv4();
const emailAdapter = {
Expand Down
56 changes: 56 additions & 0 deletions src/GraphQL/loaders/usersMutations.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as objectsMutations from '../helpers/objectsMutations';
import { OBJECT } from './defaultGraphQLTypes';
import { getUserFromSessionToken } from './usersQueries';
import { transformTypes } from '../transformers/mutation';
import Parse from 'parse/node';

const usersRouter = new UsersRouter();

Expand Down Expand Up @@ -250,6 +251,61 @@ const load = parseGraphQLSchema => {
parseGraphQLSchema.addGraphQLType(resetPasswordMutation.type, true, true);
parseGraphQLSchema.addGraphQLMutation('resetPassword', resetPasswordMutation, true, true);

const confirmResetPasswordMutation = mutationWithClientMutationId({
name: 'ConfirmResetPassword',
description:
'The confirmResetPassword mutation can be used to reset the password of an existing user.',
inputFields: {
username: {
descriptions: 'Username of the user that have received the reset email',
type: new GraphQLNonNull(GraphQLString),
},
password: {
descriptions: 'New password of the user',
type: new GraphQLNonNull(GraphQLString),
},
token: {
descriptions: 'Reset token that was emailed to the user',
type: new GraphQLNonNull(GraphQLString),
},
},
outputFields: {
ok: {
description: "It's always true.",
type: new GraphQLNonNull(GraphQLBoolean),
},
},
mutateAndGetPayload: async ({ username, password, token }, context) => {
const { config } = context;
if (!username) {
throw new Parse.Error(Parse.Error.USERNAME_MISSING, 'you must provide a username');
}
if (!password) {
throw new Parse.Error(Parse.Error.PASSWORD_MISSING, 'you must provide a password');
}
if (!token) {
throw new Parse.Error(Parse.Error.OTHER_CAUSE, 'you must provide a token');
}

const userController = config.userController;
await userController.updatePassword(username, token, password);
return { ok: true };
},
});

parseGraphQLSchema.addGraphQLType(
confirmResetPasswordMutation.args.input.type.ofType,
true,
true
);
parseGraphQLSchema.addGraphQLType(confirmResetPasswordMutation.type, true, true);
parseGraphQLSchema.addGraphQLMutation(
'confirmResetPassword',
confirmResetPasswordMutation,
true,
true
);

const sendVerificationEmailMutation = mutationWithClientMutationId({
name: 'SendVerificationEmail',
description:
Expand Down

0 comments on commit a3a00d4

Please sign in to comment.