Skip to content

Commit

Permalink
feat: user password update
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoEscaleira committed Mar 20, 2024
1 parent 0cb9ae8 commit 612bc72
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 2 deletions.
20 changes: 20 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,13 @@ type Mutation {
loginUser(input: LoginInput!): LoginResponse!
signupUser(user: SignUpInput!): UserData!

"""Update user password while logged in"""
updatePassword(userPasswordInput: PasswordUpdateInput!): Boolean!

"""Update a quiz"""
updateQuiz(quiz: QuizAddInput!, quizId: String!): QuizData!

"""Update all user details"""
updateUser(user: UserUpdateInput!, userId: String!): UserData!
}

Expand All @@ -164,6 +169,21 @@ input OptionInput {
text: String!
}

"""User update password input mutation data"""
input PasswordUpdateInput {
"""Current user password"""
currentPassword: String!

"""New user password"""
password: String!

"""New user password confirmation"""
passwordConfirm: String!

"""User id for identification"""
userId: String!
}

type Query {
attemptById(attemptId: String!): AttemptData!
attempts(quizId: String, userId: String): [AttemptData!]!
Expand Down
38 changes: 36 additions & 2 deletions src/resolvers/user.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import bcrypt from 'bcryptjs';
import config from 'config';
import { CookieOptions } from 'express';
import { GraphQLError } from 'graphql/error';
import { Arg, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql';
import UserModel from '../models/user.model';
import { LoginInput, LoginResponse, SignUpInput, UserData, UserUpdateInput } from '../schemas';
import { LoginInput, LoginResponse, SignUpInput, UserData, UserUpdateInput, PasswordUpdateInput } from '../schemas';
import { Context, Roles } from '../types';
import { errorHandler, handleForbiddenError } from '../utils/errorHandler';
import { signJwt, signTokens, verifyJwt } from '../utils/jwt';
Expand Down Expand Up @@ -121,7 +122,7 @@ export default class UserResolver {
}

@Authorized()
@Mutation(() => UserData)
@Mutation(() => UserData, { description: 'Update all user details' })
async updateUser(@Arg('userId') userId: string, @Arg('user') user: UserUpdateInput) {
try {
await UserModel.updateOne(
Expand All @@ -137,6 +138,39 @@ export default class UserResolver {
}
}

@Authorized()
@Mutation(() => Boolean, { description: 'Update user password while logged in' })
async updatePassword(@Arg('userPasswordInput') userPasswordInput: PasswordUpdateInput) {
try {
if (userPasswordInput.password !== userPasswordInput.passwordConfirm) {
return new GraphQLError('New passwords do not match.');
}

const currentUser = await UserModel.findOne({ _id: userPasswordInput.userId }).select('+password');

if (
!currentUser ||
!(await UserModel.comparePasswords(currentUser.password, userPasswordInput.currentPassword))
) {
return new GraphQLError('Current password does not match with existing password.');
}

await UserModel.updateOne(
{
_id: userPasswordInput.userId,
},
{
password: await bcrypt.hash(userPasswordInput.password, config.get<number>('costFactor')),
passwordConfirm: undefined,
},
);

return true;
} catch (error) {
errorHandler(error);
}
}

@Authorized([Roles.Admin])
@Mutation(() => Boolean, {
description:
Expand Down
27 changes: 27 additions & 0 deletions src/schemas/user/user.input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,30 @@ export class UserUpdateInput {
@Field({ nullable: true, description: 'User country' })
country?: string;
}

@InputType({ description: 'User update password input mutation data' })
export class PasswordUpdateInput {
@Field({ description: 'User id for identification' })
userId: string;

@Field({ description: 'Current user password' })
currentPassword: string;

@Field({ description: 'New user password' })
@IsStrongPassword(
{
minLength: 8,
minLowercase: 1,
minNumbers: 1,
minSymbols: 1,
minUppercase: 1,
},
{
message: 'Password is not strong enough',
},
)
password: string;

@Field({ description: 'New user password confirmation' })
passwordConfirm: string;
}

0 comments on commit 612bc72

Please sign in to comment.