mirror of
https://github.com/hknsh/project-knedita.git
synced 2024-11-28 17:41:15 +00:00
feat: added update email and password routes
This commit is contained in:
parent
e6718ca54f
commit
8af84b7cfa
4 changed files with 124 additions and 3 deletions
14
src/users/dto/update-email.dto.ts
Normal file
14
src/users/dto/update-email.dto.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { createZodDto } from "nestjs-zod";
|
||||||
|
import { z } from "nestjs-zod/z";
|
||||||
|
|
||||||
|
export const UpdateEmailSchema = z
|
||||||
|
.object({
|
||||||
|
email: z
|
||||||
|
.string({
|
||||||
|
required_error: "Email is required",
|
||||||
|
})
|
||||||
|
.email("Invalid email"),
|
||||||
|
})
|
||||||
|
.required();
|
||||||
|
|
||||||
|
export class UpdateEmailDTO extends createZodDto(UpdateEmailSchema) {}
|
33
src/users/dto/update-password.dto.ts
Normal file
33
src/users/dto/update-password.dto.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import { createZodDto } from "nestjs-zod";
|
||||||
|
import { z } from "nestjs-zod/z";
|
||||||
|
|
||||||
|
// TODO: see if it can be refactored
|
||||||
|
|
||||||
|
export const UpdatePasswordSchema = z
|
||||||
|
.object({
|
||||||
|
old_password: z
|
||||||
|
.password({
|
||||||
|
required_error: "Password is required",
|
||||||
|
})
|
||||||
|
.min(8)
|
||||||
|
.max(32)
|
||||||
|
.atLeastOne("digit")
|
||||||
|
.atLeastOne("uppercase")
|
||||||
|
.atLeastOne("lowercase")
|
||||||
|
.atLeastOne("special")
|
||||||
|
.transform((value) => value.replace(/\s+/g, "")),
|
||||||
|
new_password: z
|
||||||
|
.password({
|
||||||
|
required_error: "Password is required",
|
||||||
|
})
|
||||||
|
.min(8)
|
||||||
|
.max(32)
|
||||||
|
.atLeastOne("digit")
|
||||||
|
.atLeastOne("uppercase")
|
||||||
|
.atLeastOne("lowercase")
|
||||||
|
.atLeastOne("special")
|
||||||
|
.transform((value) => value.replace(/\s+/g, "")),
|
||||||
|
})
|
||||||
|
.required();
|
||||||
|
|
||||||
|
export class UpdatePasswordDTO extends createZodDto(UpdatePasswordSchema) {}
|
|
@ -23,6 +23,8 @@ import { CreateUserDTO } from "./dto/create-user.dto";
|
||||||
import { Public } from "src/public.decorator";
|
import { Public } from "src/public.decorator";
|
||||||
import { UpdateNameDTO } from "./dto/update-name.dto";
|
import { UpdateNameDTO } from "./dto/update-name.dto";
|
||||||
import { User } from "./types/user.type";
|
import { User } from "./types/user.type";
|
||||||
|
import { UpdateEmailDTO } from "./dto/update-email.dto";
|
||||||
|
import { UpdatePasswordDTO } from "./dto/update-password.dto";
|
||||||
|
|
||||||
@ApiTags("Users")
|
@ApiTags("Users")
|
||||||
@Controller("users")
|
@Controller("users")
|
||||||
|
@ -49,7 +51,7 @@ export class UserController {
|
||||||
description: "Not authenticated / Invalid JWT Token",
|
description: "Not authenticated / Invalid JWT Token",
|
||||||
})
|
})
|
||||||
me(@Request() req) {
|
me(@Request() req) {
|
||||||
return req.user; // TODO: Add typing to req.user
|
return req.user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Public()
|
@Public()
|
||||||
|
@ -74,12 +76,23 @@ export class UserController {
|
||||||
@Patch("/email")
|
@Patch("/email")
|
||||||
@ApiOperation({ summary: "Updates the email of a logged user" })
|
@ApiOperation({ summary: "Updates the email of a logged user" })
|
||||||
@ApiBearerAuth("JWT")
|
@ApiBearerAuth("JWT")
|
||||||
updateEmail() {}
|
updateEmail(@Body() body: UpdateEmailDTO, @Request() req) {
|
||||||
|
return this.userService.updateEmail(req.user as User, body.email);
|
||||||
|
}
|
||||||
|
|
||||||
@Patch("/password")
|
@Patch("/password")
|
||||||
@ApiOperation({ summary: "Updates the password of a logged user" })
|
@ApiOperation({ summary: "Updates the password of a logged user" })
|
||||||
@ApiBearerAuth("JWT")
|
@ApiBearerAuth("JWT")
|
||||||
updatePassword() {}
|
updatePassword(
|
||||||
|
@Body() { old_password, new_password }: UpdatePasswordDTO,
|
||||||
|
@Request() req,
|
||||||
|
) {
|
||||||
|
return this.userService.updatePassword(
|
||||||
|
req.user as User,
|
||||||
|
old_password,
|
||||||
|
new_password,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Patch("/image")
|
@Patch("/image")
|
||||||
@ApiOperation({ summary: "Add a profile image" })
|
@ApiOperation({ summary: "Add a profile image" })
|
||||||
|
|
|
@ -101,6 +101,35 @@ export class UserService {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateEmail(
|
||||||
|
loggedUser: User,
|
||||||
|
email: string,
|
||||||
|
): Promise<{ message: string }> {
|
||||||
|
const user = await this.prisma.user.findFirst({
|
||||||
|
where: { id: loggedUser.id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (email !== undefined && email.trim() !== user.email) {
|
||||||
|
const isAlreadyInUse = await this.prisma.user.findFirst({
|
||||||
|
where: { email },
|
||||||
|
});
|
||||||
|
if (isAlreadyInUse != null && isAlreadyInUse.email !== user.email) {
|
||||||
|
throw new BadRequestException("Email already in use");
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.prisma.user.update({
|
||||||
|
where: {
|
||||||
|
id: loggedUser.id,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
email: email ?? user.email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { message: "Email updated successfully" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async updateName(
|
async updateName(
|
||||||
loggedUser: User,
|
loggedUser: User,
|
||||||
username: string | undefined,
|
username: string | undefined,
|
||||||
|
@ -133,4 +162,36 @@ export class UserService {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updatePassword(
|
||||||
|
loggedUser: User,
|
||||||
|
old_password: string,
|
||||||
|
new_password: string,
|
||||||
|
): Promise<{ message: string }> {
|
||||||
|
const id = loggedUser.id;
|
||||||
|
|
||||||
|
const user = await this.prisma.user.findFirst({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
const validatePassword = await bcrypt.compare(old_password, user.password);
|
||||||
|
|
||||||
|
if (!validatePassword) {
|
||||||
|
throw new BadRequestException("Wrong password");
|
||||||
|
}
|
||||||
|
|
||||||
|
const salt = await bcrypt.genSalt(15);
|
||||||
|
const hash = await bcrypt.hash(new_password, salt);
|
||||||
|
|
||||||
|
await this.prisma.user.update({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
password: hash,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { message: "Password updated successfully" };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue