import { InternalServerErrorException , RequestTimeoutException , NotFoundException , Injectable } from '@nestjs/common' ; import { ChangePasswordRequestDto , CreateUserRequestDto , UpdateUserRequestDto , UserResponseDto } from './dtos' ; import { InvalidCurrentPasswordException , ForeignKeyConflictException , UserExistsException , } from '@common/http/exceptions' ; import { Pagination , PaginationRequest , PaginationResponseDto } from '@libs/pagination' ; import { UsersRepository } from './users.repository' ; import { InjectRepository } from '@nestjs/typeorm' ; import { DBErrorCode } from '@common/enums' ; import { UserMapper } from './users.mapper' ; import { HashHelper } from '@helpers' ; import { TimeoutError } from 'rxjs' ; @ Injectable ( ) export class UsersService { constructor ( @ InjectRepository ( UsersRepository ) private usersRepository ) { } param pagination { PaginationRequest } returns { Promise < PaginationResponseDto < UserResponseDto > > } public async getUsers ( pagination ) { try { const [ userEntities , totalUsers ] = await this . usersRepository . getUsersAndCount ( pagination ) ; const UserDtos = await Promise . all ( userEntities . map ( UserMapper . toDtoWithRelations ) ) ; return Pagination . of ( pagination , totalUsers , UserDtos ) ; } catch ( error ) { if ( error instanceof NotFoundException ) { throw new NotFoundException ( ) ; } if ( error instanceof TimeoutError ) { throw new RequestTimeoutException ( ) ; } else { throw new InternalServerErrorException ( ) ; } } } param id { string } returns { Promise < UserResponseDto > } public async getUserById ( id ) { const userEntity = await this . usersRepository . findOne ( id , { relations : [ 'permissions' , 'roles' ] , } ) ; if ( ! userEntity ) { throw new NotFoundException ( ) ; } return UserMapper . toDtoWithRelations ( userEntity ) ; } param userDto { CreateUserRequestDto } returns { Promise < UserResponseDto > } public async createUser ( userDto ) { try { let userEntity = UserMapper . toCreateEntity ( userDto ) ; userEntity . password = await HashHelper . encrypt ( userEntity . password ) ; userEntity = await this . usersRepository . save ( userEntity ) ; return UserMapper . toDto ( userEntity ) ; } catch ( error ) { if ( error . code == DBErrorCode . PgUniqueConstraintViolation ) { throw new UserExistsException ( userDto . username ) ; } if ( error . code == DBErrorCode . PgForeignKeyConstraintViolation || error . code == DBErrorCode . PgNotNullConstraintViolation ) { throw new ForeignKeyConflictException ( ) ; } if ( error instanceof TimeoutError ) { throw new RequestTimeoutException ( ) ; } else { throw new InternalServerErrorException ( ) ; } } } param id { string } param userDto { UpdateUserRequestDto } returns { Promise < UserResponseDto > } public async updateUser ( id , userDto ) { let userEntity = await this . usersRepository . findOne ( id ) ; if ( ! userEntity ) { throw new NotFoundException ( ) ; } try { userEntity = UserMapper . toUpdateEntity ( userEntity , userDto ) ; userEntity = await this . usersRepository . save ( userEntity ) ; return UserMapper . toDto ( userEntity ) ; } catch ( error ) { if ( error . code == DBErrorCode . PgUniqueConstraintViolation ) { throw new UserExistsException ( userDto . username ) ; } if ( error . code == DBErrorCode . PgForeignKeyConstraintViolation || error . code == DBErrorCode . PgNotNullConstraintViolation ) { throw new ForeignKeyConflictException ( ) ; } if ( error instanceof TimeoutError ) { throw new RequestTimeoutException ( ) ; } else { throw new InternalServerErrorException ( ) ; } } } param changePassword { ChangePasswordRequestDto } param user { string } returns { Promise < UserResponseDto > } public async changePassword ( changePassword , userId ) { const { currentPassword , newPassword } = changePassword ; const userEntity = await this . usersRepository . findOne ( { id : userId } ) ; if ( ! userEntity ) { throw new NotFoundException ( ) ; } const passwordMatch = await HashHelper . compare ( currentPassword , userEntity . password ) ; if ( ! passwordMatch ) { throw new InvalidCurrentPasswordException ( ) ; } try { userEntity . password = await HashHelper . encrypt ( newPassword ) ; await this . usersRepository . save ( userEntity ) ; return UserMapper . toDto ( userEntity ) ; } catch ( error ) { if ( error instanceof TimeoutError ) { throw new RequestTimeoutException ( ) ; } else { throw new InternalServerErrorException ( ) ; } } } }