From 6a5cc243ea7c8d95838dee7beb7a7b98079b23ce Mon Sep 17 00:00:00 2001 From: Devstack Date: Sat, 4 Jun 2022 10:26:11 +0200 Subject: [PATCH 1/7] dev - add avatar column - try to upload file avatar - add edit user service - add edit user controller and avatar upload - add avatar to entity - update user dto --- package.json | 1 + src/components/users/dto/update-user.dto.ts | 17 +++++++++ src/components/users/entities/user.entity.ts | 7 +++- src/components/users/users.controller.ts | 37 ++++++++++++++++++- src/components/users/users.service.ts | 6 +++ .../1654328367398-AddAvatarColumnToUser.ts | 19 ++++++++++ yarn.lock | 7 ++++ 7 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 src/components/users/dto/update-user.dto.ts create mode 100644 src/migrations/1654328367398-AddAvatarColumnToUser.ts diff --git a/package.json b/package.json index f9e8bac..0bc766c 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "@nestjs/testing": "^8.0.0", "@types/express": "^4.17.13", "@types/jest": "27.0.2", + "@types/multer": "^1.4.7", "@types/node": "^16.0.0", "@types/supertest": "^2.0.11", "@typescript-eslint/eslint-plugin": "^5.0.0", diff --git a/src/components/users/dto/update-user.dto.ts b/src/components/users/dto/update-user.dto.ts new file mode 100644 index 0000000..61e8aa4 --- /dev/null +++ b/src/components/users/dto/update-user.dto.ts @@ -0,0 +1,17 @@ +import { IsNotEmpty, IsBoolean, IsEmail, Allow } from 'class-validator'; +export class UpdateUserDto { + @IsEmail() + email: string; + + @IsNotEmpty() + username: string; + + @IsBoolean() + is_active: boolean; + + @Allow() + firstname: string; + + @Allow() + lastname: string; +} diff --git a/src/components/users/entities/user.entity.ts b/src/components/users/entities/user.entity.ts index 72cde85..6386941 100644 --- a/src/components/users/entities/user.entity.ts +++ b/src/components/users/entities/user.entity.ts @@ -14,12 +14,15 @@ export class Users { @Column() username: string; - @Column({ nullable: true }) + @Column({ nullable: true, default: null }) firstname: string; - @Column({ nullable: true }) + @Column({ nullable: true, default: null }) lastname: string; + @Column({ nullable: true, default: null }) + avatar: string; + @Column({ type: 'boolean', default: true }) is_active: boolean; diff --git a/src/components/users/users.controller.ts b/src/components/users/users.controller.ts index ad19dd4..20912bc 100644 --- a/src/components/users/users.controller.ts +++ b/src/components/users/users.controller.ts @@ -2,14 +2,21 @@ import { Controller, HttpStatus, Get, + Post, + Patch, + Delete, Res, Body, Param, UseGuards, + UseInterceptors, + UploadedFile, } from '@nestjs/common'; -import { Post } from '@nestjs/common/decorators/http'; +import { Express } from 'express'; +import { FileInterceptor } from '@nestjs/platform-express'; import { JwtAuthGuard } from '../auth/guard/jwt-auth.guard'; import { CreateUserDto } from './dto/create-user.dto'; +import { UpdateUserDto } from './dto/update-user.dto'; import { UsersService } from './users.service'; @Controller('users') @@ -27,7 +34,7 @@ export class UsersController { async addUser(@Res() res, @Body() createUserDto: CreateUserDto) { const newUser = await this.userService.create(createUserDto); return res.status(HttpStatus.OK).json({ - message: 'User has been submitted successfully!', + message: 'User has been created successfully!', user: newUser, }); } @@ -37,4 +44,30 @@ export class UsersController { const user = await this.userService.findOne({ where: { id: userId } }); return res.status(HttpStatus.OK).json(user); } + + @Delete(':id') + async deleteUser(@Res() res, @Param('id') userId) { + await this.userService.remove(userId); + return res.status(HttpStatus.OK).json({ + message: 'User has been deleted successfully!', + }); + } + + @Patch(':id') + async editUser( + @Res() res, + @Param('id') userId, + @Body() updateUserDto: UpdateUserDto, + ) { + await this.userService.edit(userId, updateUserDto); + return res.status(HttpStatus.OK).json({ + message: 'User has been updated successfully!', + }); + } + + @Post('/avatar/:id') + @UseInterceptors(FileInterceptor('avatar')) + uploadAvatar(@UploadedFile() file: Express.Multer.File) { + console.log(file); + } } diff --git a/src/components/users/users.service.ts b/src/components/users/users.service.ts index 58d0245..8854c43 100644 --- a/src/components/users/users.service.ts +++ b/src/components/users/users.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { CreateUserDto } from './dto/create-user.dto'; +import { UpdateUserDto } from './dto/update-user.dto'; import { Users as User } from './entities/user.entity'; import * as bcrypt from 'bcrypt'; @@ -28,4 +29,9 @@ export class UsersService { async remove(id: string): Promise { await this.usersRepository.delete(id); } + + async edit(id: string, updateUserDto: UpdateUserDto): Promise { + console.log(updateUserDto) + await this.usersRepository.update(id, updateUserDto); + } } diff --git a/src/migrations/1654328367398-AddAvatarColumnToUser.ts b/src/migrations/1654328367398-AddAvatarColumnToUser.ts new file mode 100644 index 0000000..c1025f9 --- /dev/null +++ b/src/migrations/1654328367398-AddAvatarColumnToUser.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; + +export class AddAvatarColumnToUser1654328367398 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.addColumn( + 'users', + new TableColumn({ + name: 'avatar', + type: 'varchar', + isNullable: true, + default: null, + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropColumn('users', 'avatar'); + } +} diff --git a/yarn.lock b/yarn.lock index 4d8d96c..64e80bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -978,6 +978,13 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== +"@types/multer@^1.4.7": + version "1.4.7" + resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.7.tgz#89cf03547c28c7bbcc726f029e2a76a7232cc79e" + integrity sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA== + dependencies: + "@types/express" "*" + "@types/node@*": version "17.0.35" resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.35.tgz#635b7586086d51fb40de0a2ec9d1014a5283ba4a" From 55533d2cce1cdb32bac9a177d7e8bce7b26ab09f Mon Sep 17 00:00:00 2001 From: Devstack Date: Sat, 4 Jun 2022 16:12:35 +0200 Subject: [PATCH 2/7] upload avatars v1 --- src/app.controller.ts | 8 ++++---- src/app.module.ts | 4 ++++ src/app.service.ts | 3 --- src/components/users/users.controller.ts | 18 ++++++++++++++++-- src/utils/file-upload.utils.ts | 18 ++++++++++++++++++ uploads/avatars/logo2-6b5f.png | Bin 0 -> 4997 bytes 6 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 src/utils/file-upload.utils.ts create mode 100644 uploads/avatars/logo2-6b5f.png diff --git a/src/app.controller.ts b/src/app.controller.ts index de37367..ce77371 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,12 +1,12 @@ -import { Controller, Get } from '@nestjs/common'; +import { Controller, Get, Param, Res } from '@nestjs/common'; import { AppService } from './app.service'; @Controller() export class AppController { constructor(private readonly appService: AppService) {} - @Get() - GetHello(): string { - return this.appService.getHello(); + @Get('avatars/:imgpath') + seeUploadedFile(@Param('imgpath') image, @Res() res) { + return res.sendFile(image, { root: './uploads/avatars' }); } } \ No newline at end of file diff --git a/src/app.module.ts b/src/app.module.ts index 47c6ecc..e51d3b5 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -10,9 +10,13 @@ import { Books } from './components/books/entities/book.entity'; import { AuthModule } from './components/auth/auth.module'; import { APP_INTERCEPTOR } from '@nestjs/core'; import { AuthInterceptor } from './interceptor/auth.interceptor'; +import { MulterModule } from '@nestjs/platform-express'; @Module({ imports: [ + MulterModule.register({ + dest: './uploads', + }), ConfigModule.forRoot({ isGlobal: true, }), diff --git a/src/app.service.ts b/src/app.service.ts index 927d7cc..a031ef5 100644 --- a/src/app.service.ts +++ b/src/app.service.ts @@ -2,7 +2,4 @@ import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { - getHello(): string { - return 'Hello World!'; - } } diff --git a/src/components/users/users.controller.ts b/src/components/users/users.controller.ts index 20912bc..d7b2c01 100644 --- a/src/components/users/users.controller.ts +++ b/src/components/users/users.controller.ts @@ -18,6 +18,8 @@ import { JwtAuthGuard } from '../auth/guard/jwt-auth.guard'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { UsersService } from './users.service'; +import { diskStorage } from 'multer'; +import { editFileName, imageFileFilter } from 'src/utils/file-upload.utils'; @Controller('users') export class UsersController { @@ -66,8 +68,20 @@ export class UsersController { } @Post('/avatar/:id') - @UseInterceptors(FileInterceptor('avatar')) + @UseInterceptors( + FileInterceptor('avatar', { + storage: diskStorage({ + destination: './uploads/avatars', + filename: editFileName, + }), + fileFilter: imageFileFilter, + }), + ) uploadAvatar(@UploadedFile() file: Express.Multer.File) { - console.log(file); + const response = { + originalname: file.originalname, + filename: file.filename, + }; + return response; } } diff --git a/src/utils/file-upload.utils.ts b/src/utils/file-upload.utils.ts new file mode 100644 index 0000000..8e1367b --- /dev/null +++ b/src/utils/file-upload.utils.ts @@ -0,0 +1,18 @@ +import { extname } from "path"; + +export const imageFileFilter = (req, file, callback) => { + if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) { + return callback(new Error('Only image files are allowed!'), false); + } + callback(null, true); +}; + +export const editFileName = (req, file, callback) => { + const name = file.originalname.split('.')[0]; + const fileExtName = extname(file.originalname); + const randomName = Array(4) + .fill(null) + .map(() => Math.round(Math.random() * 16).toString(16)) + .join(''); + callback(null, `${name}-${randomName}${fileExtName}`); +}; \ No newline at end of file diff --git a/uploads/avatars/logo2-6b5f.png b/uploads/avatars/logo2-6b5f.png new file mode 100644 index 0000000000000000000000000000000000000000..5f22a45827d09deab037a7efa62c6091ebf58647 GIT binary patch literal 4997 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 Date: Sat, 4 Jun 2022 17:13:52 +0200 Subject: [PATCH 3/7] Delete uploads directory --- uploads/avatars/logo2-6b5f.png | Bin 4997 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 uploads/avatars/logo2-6b5f.png diff --git a/uploads/avatars/logo2-6b5f.png b/uploads/avatars/logo2-6b5f.png deleted file mode 100644 index 5f22a45827d09deab037a7efa62c6091ebf58647..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4997 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 Date: Sat, 4 Jun 2022 20:31:51 +0200 Subject: [PATCH 4/7] remove password from selecting --- .gitignore | 4 +++- src/components/users/dto/create-user.dto.ts | 10 +++++++++- src/components/users/dto/update-user.dto.ts | 14 +++++++++++--- src/components/users/entities/user.entity.ts | 3 ++- src/components/users/users.controller.ts | 12 ++++++++---- src/utils/file-upload.utils.ts | 12 ++++++++---- 6 files changed, 41 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index d8aaabb..3086bca 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,6 @@ lerna-debug.log* !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -ormconfig.json \ No newline at end of file +ormconfig.json + +uploads/* \ No newline at end of file diff --git a/src/components/users/dto/create-user.dto.ts b/src/components/users/dto/create-user.dto.ts index ecaab0a..c6d44df 100644 --- a/src/components/users/dto/create-user.dto.ts +++ b/src/components/users/dto/create-user.dto.ts @@ -1,4 +1,4 @@ -import { IsNotEmpty, IsBoolean, IsEmail } from 'class-validator'; +import { IsNotEmpty, IsBoolean, IsEmail, IsString, IsOptional } from 'class-validator'; export class CreateUserDto { @IsEmail() email: string; @@ -9,6 +9,14 @@ export class CreateUserDto { @IsNotEmpty() username: string; + @IsString() + @IsOptional() + firstname: string; + + @IsString() + @IsOptional() + lastname: string; + @IsBoolean() is_active: boolean; } diff --git a/src/components/users/dto/update-user.dto.ts b/src/components/users/dto/update-user.dto.ts index 61e8aa4..abacbaf 100644 --- a/src/components/users/dto/update-user.dto.ts +++ b/src/components/users/dto/update-user.dto.ts @@ -1,4 +1,10 @@ -import { IsNotEmpty, IsBoolean, IsEmail, Allow } from 'class-validator'; +import { + IsNotEmpty, + IsBoolean, + IsEmail, + IsString, + IsOptional, +} from 'class-validator'; export class UpdateUserDto { @IsEmail() email: string; @@ -9,9 +15,11 @@ export class UpdateUserDto { @IsBoolean() is_active: boolean; - @Allow() + @IsString() + @IsOptional() firstname: string; - @Allow() + @IsString() + @IsOptional() lastname: string; } diff --git a/src/components/users/entities/user.entity.ts b/src/components/users/entities/user.entity.ts index 6386941..f0c5f1e 100644 --- a/src/components/users/entities/user.entity.ts +++ b/src/components/users/entities/user.entity.ts @@ -1,5 +1,6 @@ import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm'; import { Books as Book } from 'src/components/books/entities/book.entity'; +import { Exclude } from 'class-transformer'; @Entity() export class Users { @PrimaryGeneratedColumn('increment') @@ -8,7 +9,7 @@ export class Users { @Column({ unique: true }) email: string; - @Column() + @Column({select: false}) password: string; @Column() diff --git a/src/components/users/users.controller.ts b/src/components/users/users.controller.ts index d7b2c01..68810e5 100644 --- a/src/components/users/users.controller.ts +++ b/src/components/users/users.controller.ts @@ -32,6 +32,7 @@ export class UsersController { return res.status(HttpStatus.OK).json(users); } + @UseGuards(JwtAuthGuard) @Post() async addUser(@Res() res, @Body() createUserDto: CreateUserDto) { const newUser = await this.userService.create(createUserDto); @@ -40,13 +41,13 @@ export class UsersController { user: newUser, }); } - +@UseGuards(JwtAuthGuard) @Get(':id') async getUser(@Res() res, @Param('id') userId) { const user = await this.userService.findOne({ where: { id: userId } }); return res.status(HttpStatus.OK).json(user); } - + @UseGuards(JwtAuthGuard) @Delete(':id') async deleteUser(@Res() res, @Param('id') userId) { await this.userService.remove(userId); @@ -54,7 +55,7 @@ export class UsersController { message: 'User has been deleted successfully!', }); } - + @UseGuards(JwtAuthGuard) @Patch(':id') async editUser( @Res() res, @@ -66,7 +67,7 @@ export class UsersController { message: 'User has been updated successfully!', }); } - + @UseGuards(JwtAuthGuard) @Post('/avatar/:id') @UseInterceptors( FileInterceptor('avatar', { @@ -75,6 +76,9 @@ export class UsersController { filename: editFileName, }), fileFilter: imageFileFilter, + limits: { + fileSize: Math.pow(1024, 2) + } }), ) uploadAvatar(@UploadedFile() file: Express.Multer.File) { diff --git a/src/utils/file-upload.utils.ts b/src/utils/file-upload.utils.ts index 8e1367b..85bd4ed 100644 --- a/src/utils/file-upload.utils.ts +++ b/src/utils/file-upload.utils.ts @@ -1,8 +1,12 @@ -import { extname } from "path"; +import { BadRequestException } from '@nestjs/common'; +import { extname } from 'path'; export const imageFileFilter = (req, file, callback) => { - if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) { - return callback(new Error('Only image files are allowed!'), false); + if (!file.mimetype.includes('image')) { + return callback( + new BadRequestException('Please, provide a valid image'), + false, + ); } callback(null, true); }; @@ -15,4 +19,4 @@ export const editFileName = (req, file, callback) => { .map(() => Math.round(Math.random() * 16).toString(16)) .join(''); callback(null, `${name}-${randomName}${fileExtName}`); -}; \ No newline at end of file +}; From 11ac394eae8ab1d4ca1edff18994a1ca4a87110b Mon Sep 17 00:00:00 2001 From: Devstack Date: Sat, 4 Jun 2022 22:11:30 +0200 Subject: [PATCH 5/7] avatar v2, fix password --- src/components/auth/auth.service.ts | 16 +++++++++------ src/components/users/entities/user.entity.ts | 4 ++-- src/components/users/users.controller.ts | 21 +++++++++++--------- src/components/users/users.service.ts | 6 ++++++ 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/components/auth/auth.service.ts b/src/components/auth/auth.service.ts index b3391b3..fb74c6d 100644 --- a/src/components/auth/auth.service.ts +++ b/src/components/auth/auth.service.ts @@ -11,12 +11,16 @@ export class AuthService { ) {} async validateUser(email: string, pass: string): Promise { - const user = await this.usersService.findOne({ where: { email: email } }); - if (!user) return null; + const user = await this.usersService.findOne({ + where: { email: email }, + select: ['id', 'password'], + }); + if (!user || !user.password) return null; const validPassword = await bcrypt.compare(pass, user.password); - if (user && validPassword) { - const { password, ...result } = user; - return result; + if (validPassword) { + return await this.usersService.findOne({ + where: { id: user.id }, + }); } return null; } @@ -32,7 +36,7 @@ export class AuthService { }, }; return { - user: payload.user, + user: req.user, access_token: this.jwtService.sign(payload), }; } diff --git a/src/components/users/entities/user.entity.ts b/src/components/users/entities/user.entity.ts index f0c5f1e..43d4d41 100644 --- a/src/components/users/entities/user.entity.ts +++ b/src/components/users/entities/user.entity.ts @@ -1,6 +1,6 @@ import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm'; import { Books as Book } from 'src/components/books/entities/book.entity'; -import { Exclude } from 'class-transformer'; + @Entity() export class Users { @PrimaryGeneratedColumn('increment') @@ -9,7 +9,7 @@ export class Users { @Column({ unique: true }) email: string; - @Column({select: false}) + @Column({ select: false }) password: string; @Column() diff --git a/src/components/users/users.controller.ts b/src/components/users/users.controller.ts index 68810e5..be854c3 100644 --- a/src/components/users/users.controller.ts +++ b/src/components/users/users.controller.ts @@ -41,7 +41,7 @@ export class UsersController { user: newUser, }); } -@UseGuards(JwtAuthGuard) + @UseGuards(JwtAuthGuard) @Get(':id') async getUser(@Res() res, @Param('id') userId) { const user = await this.userService.findOne({ where: { id: userId } }); @@ -77,15 +77,18 @@ export class UsersController { }), fileFilter: imageFileFilter, limits: { - fileSize: Math.pow(1024, 2) - } + fileSize: Math.pow(1024, 2), + }, }), ) - uploadAvatar(@UploadedFile() file: Express.Multer.File) { - const response = { - originalname: file.originalname, - filename: file.filename, - }; - return response; + async uploadAvatar( + @Res() res, + @Param('id') userId, + @UploadedFile() file: Express.Multer.File, + ) { + await this.userService.editAvatar(userId, file.filename); + return res.status(HttpStatus.OK).json({ + message: 'Avatar has been uploaded successfully!', + }); } } diff --git a/src/components/users/users.service.ts b/src/components/users/users.service.ts index 8854c43..d312014 100644 --- a/src/components/users/users.service.ts +++ b/src/components/users/users.service.ts @@ -34,4 +34,10 @@ export class UsersService { console.log(updateUserDto) await this.usersRepository.update(id, updateUserDto); } + + async editAvatar(id: string, fileName: string): Promise { + await this.usersRepository.update(id, { + avatar: fileName, + }); + } } From 97f214d9260915be055739aa8a6e556936f10f54 Mon Sep 17 00:00:00 2001 From: Devstack Date: Sun, 5 Jun 2022 09:26:39 +0200 Subject: [PATCH 6/7] remove books --- src/app.module.ts | 5 +- src/components/books/books.controller.spec.ts | 20 ------ src/components/books/books.controller.ts | 72 ------------------- src/components/books/books.module.ts | 12 ---- src/components/books/books.service.spec.ts | 18 ----- src/components/books/books.service.ts | 38 ---------- src/components/books/dto/create-book.dto.ts | 12 ---- src/components/books/dto/update-book.dto.ts | 6 -- src/components/books/entities/book.entity.ts | 28 -------- src/components/users/entities/user.entity.ts | 9 ++- src/components/users/users.service.ts | 2 +- 11 files changed, 8 insertions(+), 214 deletions(-) delete mode 100644 src/components/books/books.controller.spec.ts delete mode 100644 src/components/books/books.controller.ts delete mode 100644 src/components/books/books.module.ts delete mode 100644 src/components/books/books.service.spec.ts delete mode 100644 src/components/books/books.service.ts delete mode 100644 src/components/books/dto/create-book.dto.ts delete mode 100644 src/components/books/dto/update-book.dto.ts delete mode 100644 src/components/books/entities/book.entity.ts diff --git a/src/app.module.ts b/src/app.module.ts index e51d3b5..b3397ba 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -5,8 +5,6 @@ import { AppService } from './app.service'; import { Users } from './components/users/entities/user.entity'; import { UsersModule } from './components/users/users.module'; import { ConfigModule } from '@nestjs/config'; -import { BooksModule } from './components/books/books.module'; -import { Books } from './components/books/entities/book.entity'; import { AuthModule } from './components/auth/auth.module'; import { APP_INTERCEPTOR } from '@nestjs/core'; import { AuthInterceptor } from './interceptor/auth.interceptor'; @@ -21,12 +19,11 @@ import { MulterModule } from '@nestjs/platform-express'; isGlobal: true, }), TypeOrmModule.forRoot({ - entities: [Users, Books], + entities: [Users], synchronize: false, }), AuthModule, UsersModule, - BooksModule, ], controllers: [AppController], providers: [ diff --git a/src/components/books/books.controller.spec.ts b/src/components/books/books.controller.spec.ts deleted file mode 100644 index 2c73406..0000000 --- a/src/components/books/books.controller.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { BooksController } from './books.controller'; -import { BooksService } from './books.service'; - -describe('BooksController', () => { - let controller: BooksController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [BooksController], - providers: [BooksService], - }).compile(); - - controller = module.get(BooksController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/src/components/books/books.controller.ts b/src/components/books/books.controller.ts deleted file mode 100644 index a3867f6..0000000 --- a/src/components/books/books.controller.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { - Controller, - Get, - Post, - Body, - Patch, - Param, - Delete, - Res, - HttpStatus, - UseGuards, -} from '@nestjs/common'; -import { Response } from 'express'; -import { JwtAuthGuard } from '../auth/guard/jwt-auth.guard'; -import { BooksService } from './books.service'; -import { CreateBookDto } from './dto/create-book.dto'; -import { UpdateBookDto } from './dto/update-book.dto'; -import { Books as Book } from './entities/book.entity'; - -@Controller('books') -export class BooksController { - constructor(private readonly booksService: BooksService) {} - - @UseGuards(JwtAuthGuard) - @Post() - create(@Body() createBookDto: CreateBookDto, @Res() res: Response) { - return this.booksService.create(createBookDto); - } - - @Get() - findAll() { - return this.booksService.findAll(); - } - - @Get(':id') - async findOne( - @Param('id') id: string, - @Res() res: Response, - ): Promise { - const book = await this.booksService.findOne(+id); - if (book) return res.status(HttpStatus.OK).json(book); - return res - .status(HttpStatus.NOT_FOUND) - .json({ error: 'This resource no longer exist or has been removed' }); - } - - @UseGuards(JwtAuthGuard) - @Patch(':id') - async update( - @Param('id') id: string, - @Body() updateBookDto: UpdateBookDto, - @Res() res: Response, - ) { - const response = await this.booksService.update(+id, updateBookDto); - if (response) - return res - .status(HttpStatus.OK) - .json({ message: 'Book information updated successfully' }); - return res - .status(HttpStatus.NOT_FOUND) - .json({ error: 'The resource to be updated no longer exist' }); - } - - @UseGuards(JwtAuthGuard) - @Delete(':id') - async remove(@Param('id') id: string, @Res() res: Response) { - await this.booksService.remove(+id); - res - .status(HttpStatus.OK) - .json({ message: 'Book details deleted successfully' }); - } -} diff --git a/src/components/books/books.module.ts b/src/components/books/books.module.ts deleted file mode 100644 index bc36036..0000000 --- a/src/components/books/books.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common'; -import { BooksService } from './books.service'; -import { BooksController } from './books.controller'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { Books } from './entities/book.entity'; - -@Module({ - imports: [TypeOrmModule.forFeature([Books])], - controllers: [BooksController], - providers: [BooksService], -}) -export class BooksModule {} diff --git a/src/components/books/books.service.spec.ts b/src/components/books/books.service.spec.ts deleted file mode 100644 index 6343e6b..0000000 --- a/src/components/books/books.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { BooksService } from './books.service'; - -describe('BooksService', () => { - let service: BooksService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [BooksService], - }).compile(); - - service = module.get(BooksService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/src/components/books/books.service.ts b/src/components/books/books.service.ts deleted file mode 100644 index 4f03ff8..0000000 --- a/src/components/books/books.service.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository, UpdateResult } from 'typeorm'; -import { Books as Book } from './entities/book.entity'; - -@Injectable() -export class BooksService { - constructor( - @InjectRepository(Book) - private booksRepository: Repository, - ) {} - - async create(data: object) { - return await this.booksRepository.save(data).then((res) => res); - } - - findAll(): Promise { - return this.booksRepository.find(); - } - - findOne(id: number): Promise { - return this.booksRepository.findOne({ where: { id: id } }); - } - - async update( - id: number, - data: object, - ): Promise { - const book = await this.findOne(id).then((res) => res); - if (book) - return await this.booksRepository.update(id, data).then((res) => res); - return; - } - - async remove(id: number) { - return await this.booksRepository.delete(id); - } -} diff --git a/src/components/books/dto/create-book.dto.ts b/src/components/books/dto/create-book.dto.ts deleted file mode 100644 index e3b5d48..0000000 --- a/src/components/books/dto/create-book.dto.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { IsNotEmpty, IsBoolean, IsEmail } from 'class-validator'; - -export class CreateBookDto { - @IsNotEmpty() - title: string; - @IsNotEmpty() - description: number; - - thumbnail: string; - - author: string[]; -} diff --git a/src/components/books/dto/update-book.dto.ts b/src/components/books/dto/update-book.dto.ts deleted file mode 100644 index 883336e..0000000 --- a/src/components/books/dto/update-book.dto.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { OmitType } from '@nestjs/mapped-types'; -import { CreateBookDto } from './create-book.dto'; - -export class UpdateBookDto extends OmitType(CreateBookDto, [] as const) { - id: number; -} diff --git a/src/components/books/entities/book.entity.ts b/src/components/books/entities/book.entity.ts deleted file mode 100644 index 1a5ab75..0000000 --- a/src/components/books/entities/book.entity.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm'; -import { Users as User } from 'src/components/users/entities/user.entity'; -@Entity() -export class Books { - @PrimaryGeneratedColumn() - id: number; - - @Column() - title: string; - - @Column() - description: string; - - @Column() - thumbnail: string; - - @Column() - author: string; - - @Column({ type: 'datetime', default: null }) - created_at?: Date; - - @Column({ type: 'datetime', default: null }) - updated_at?: Date; - - @ManyToOne(() => User, (user) => user.books) - user: User; -} diff --git a/src/components/users/entities/user.entity.ts b/src/components/users/entities/user.entity.ts index 43d4d41..d14c323 100644 --- a/src/components/users/entities/user.entity.ts +++ b/src/components/users/entities/user.entity.ts @@ -1,5 +1,5 @@ import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm'; -import { Books as Book } from 'src/components/books/entities/book.entity'; +//import { Books as Book } from 'src/components/books/entities/book.entity'; @Entity() export class Users { @@ -21,6 +21,9 @@ export class Users { @Column({ nullable: true, default: null }) lastname: string; + @Column() + testee: string; + @Column({ nullable: true, default: null }) avatar: string; @@ -33,6 +36,6 @@ export class Users { @Column({ type: 'datetime', default: null }) updated_at?: Date; - @OneToMany(() => Book, (book) => book.user) - books?: Book[]; +/* @OneToMany(() => Book, (book) => book.user) + books?: Book[]; */ } diff --git a/src/components/users/users.service.ts b/src/components/users/users.service.ts index d312014..3790c80 100644 --- a/src/components/users/users.service.ts +++ b/src/components/users/users.service.ts @@ -14,7 +14,7 @@ export class UsersService { ) {} findAll(): Promise { - return this.usersRepository.find({ relations: ['books'] }); + return this.usersRepository.find(); } async findOne(data: number | any): Promise { From a84dee00634c75c525fa4a67844f190c8db85d18 Mon Sep 17 00:00:00 2001 From: devstack-be Date: Sun, 5 Jun 2022 10:42:19 +0200 Subject: [PATCH 7/7] valid password --- src/components/auth/auth.controller.ts | 6 ++-- src/components/users/dto/register-user-dto.ts | 20 +++++++++++ src/components/users/entities/user.entity.ts | 3 -- src/components/users/users.service.ts | 3 +- src/decorators/match.decorator.ts | 33 +++++++++++++++++++ 5 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 src/components/users/dto/register-user-dto.ts create mode 100644 src/decorators/match.decorator.ts diff --git a/src/components/auth/auth.controller.ts b/src/components/auth/auth.controller.ts index 1a01518..af84f44 100644 --- a/src/components/auth/auth.controller.ts +++ b/src/components/auth/auth.controller.ts @@ -8,7 +8,7 @@ import { Res, UseGuards, } from '@nestjs/common'; -import { CreateUserDto } from '../users/dto/create-user.dto'; +import { RegisterUserDto } from '../users/dto/register-user-dto'; import { AuthService } from './auth.service'; import { JwtAuthGuard } from './guard/jwt-auth.guard'; import { LocalAuthGuard } from './guard/local-auth.guard'; @@ -24,8 +24,8 @@ export class AuthController { } @Post('register') - async register(@Body() createUserDto: CreateUserDto) { - return this.authService.register(createUserDto); + async register(@Body() registerUserDto: RegisterUserDto) { + return this.authService.register(registerUserDto); } @UseGuards(JwtAuthGuard) diff --git a/src/components/users/dto/register-user-dto.ts b/src/components/users/dto/register-user-dto.ts new file mode 100644 index 0000000..ba2b6c1 --- /dev/null +++ b/src/components/users/dto/register-user-dto.ts @@ -0,0 +1,20 @@ +import { IsNotEmpty, IsEmail, IsString } from 'class-validator'; +import { Match } from 'src/decorators/match.decorator'; +export class RegisterUserDto { + @IsNotEmpty() + @IsEmail() + email: string; + + @IsNotEmpty() + @IsString() + password: string; + + @IsNotEmpty() + @IsString() + @Match('password') + confirm_password: string; + + @IsNotEmpty() + @IsString() + username: string; +} diff --git a/src/components/users/entities/user.entity.ts b/src/components/users/entities/user.entity.ts index d14c323..04548b0 100644 --- a/src/components/users/entities/user.entity.ts +++ b/src/components/users/entities/user.entity.ts @@ -21,9 +21,6 @@ export class Users { @Column({ nullable: true, default: null }) lastname: string; - @Column() - testee: string; - @Column({ nullable: true, default: null }) avatar: string; diff --git a/src/components/users/users.service.ts b/src/components/users/users.service.ts index 3790c80..10c600d 100644 --- a/src/components/users/users.service.ts +++ b/src/components/users/users.service.ts @@ -5,6 +5,7 @@ import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { Users as User } from './entities/user.entity'; import * as bcrypt from 'bcrypt'; +import { RegisterUserDto } from './dto/register-user-dto'; @Injectable() export class UsersService { @@ -21,7 +22,7 @@ export class UsersService { return await this.usersRepository.findOne(data); } - async create(createUserDto: CreateUserDto): Promise { + async create(createUserDto: CreateUserDto | RegisterUserDto): Promise { createUserDto.password = await bcrypt.hash(createUserDto.password, 10); return this.usersRepository.save(createUserDto); } diff --git a/src/decorators/match.decorator.ts b/src/decorators/match.decorator.ts new file mode 100644 index 0000000..bef0284 --- /dev/null +++ b/src/decorators/match.decorator.ts @@ -0,0 +1,33 @@ +import { + registerDecorator, + ValidationArguments, + ValidationOptions, + ValidatorConstraint, + ValidatorConstraintInterface, +} from 'class-validator'; + +export function Match(property: string, validationOptions?: ValidationOptions) { + return (object: any, propertyName: string) => { + registerDecorator({ + target: object.constructor, + propertyName, + options: validationOptions, + constraints: [property], + validator: MatchConstraint, + }); + }; +} + +@ValidatorConstraint({ name: 'Match' }) +export class MatchConstraint implements ValidatorConstraintInterface { + validate(value: any, args: ValidationArguments) { + const [relatedPropertyName] = args.constraints; + const relatedValue = (args.object as any)[relatedPropertyName]; + return value === relatedValue; + } + + defaultMessage(args: ValidationArguments) { + const [relatedPropertyName] = args.constraints; + return `${relatedPropertyName} and ${args.property} don't match`; + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy