Merge branch 'user'

This commit is contained in:
Jeremy Yin 2019-07-02 22:25:12 +08:00
commit 610747a8d6
10 changed files with 193 additions and 1 deletions

View File

@ -24,6 +24,9 @@
"@nestjs/core": "^6.0.0",
"@nestjs/platform-express": "^6.0.0",
"@nestjs/typeorm": "^6.1.2",
"@types/bcrypt": "^3.0.0",
"bcrypt": "^3.0.6",
"class-transformer": "^0.2.3",
"mysql": "^2.17.1",
"reflect-metadata": "^0.1.12",
"rimraf": "^2.6.2",

View File

@ -3,6 +3,7 @@ import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PostModule } from './modules/post/post.module';
import { UserModule } from './modules/user/user.module';
@Module({
imports: [
@ -17,6 +18,7 @@ import { PostModule } from './modules/post/post.module';
entities: [__dirname + '/**/*.entity{.ts,.js}'],
}),
PostModule,
UserModule,
],
controllers: [AppController],
providers: [AppService],

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UserController } from './user.controller';
describe('User Controller', () => {
let controller: UserController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [UserController],
}).compile();
controller = module.get<UserController>(UserController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@ -0,0 +1,27 @@
import { Controller, Post, Body, Get, Param, UseInterceptors, ClassSerializerInterceptor, Put } from '@nestjs/common';
import { UserService } from './user.service';
import { UserDto, UpdatePasswordDto } from './user.dto';
@Controller('users')
export class UserController {
constructor(
private readonly userService: UserService,
) {}
@Post()
async store(@Body() data: UserDto) {
return await this.userService.store(data);
}
@Get(':id')
@UseInterceptors(ClassSerializerInterceptor)
async show(@Param('id') id: string) {
return await this.userService.show(id);
}
@Put(':id/password')
@UseInterceptors(ClassSerializerInterceptor)
async updatePassword(@Param('id') id: string, @Body() data: UpdatePasswordDto) {
return await this.userService.updatePassword(id, data)
}
}

View File

@ -0,0 +1,9 @@
export class UserDto {
readonly username: string;
readonly password: string;
}
export class UpdatePasswordDto {
readonly password: string;
readonly newPassword: string;
}

View File

@ -0,0 +1,32 @@
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, BeforeInsert, BeforeUpdate } from 'typeorm';
import * as bcrypt from 'bcrypt';
import { Exclude } from 'class-transformer';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column('varchar', { unique: true })
username: string;
@Column('longtext', { nullable: true })
@Exclude()
password: string;
@CreateDateColumn()
created: Date;
@UpdateDateColumn()
updated: Date;
@BeforeInsert()
@BeforeUpdate()
async hashPassword() {
this.password = await bcrypt.hash(this.password, 10);
}
async comparePassword(password: string) {
return await bcrypt.compare(password, this.password);
}
}

View File

@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
@Module({
imports: [
TypeOrmModule.forFeature([User]),
],
controllers: [UserController],
providers: [UserService]
})
export class UserModule {}

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';
describe('UserService', () => {
let service: UserService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UserService],
}).compile();
service = module.get<UserService>(UserService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -0,0 +1,46 @@
import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
import { UserDto, UpdatePasswordDto } from './user.dto';
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) { }
async store(data: UserDto) {
const { username } = data;
const user = await this.userRepository.findOne({ username });
if (user) {
throw new BadRequestException('用户已经存在');
}
const entity = await this.userRepository.create(data);
await this.userRepository.save(entity);
return entity;
}
async show(id: string) {
const entity = await this.userRepository.findOne(id);
if (!entity) {
throw new NotFoundException('没有找到用户');
}
return entity;
}
async updatePassword(id: string, data: UpdatePasswordDto) {
const { password, newPassword } = data;
const entity = await this.userRepository.findOne(id)
if (!entity) {
throw new NotFoundException('没有找到用户')
}
const match = await entity.comparePassword(password)
if (!match) {
throw new BadRequestException('密码错误')
}
entity.password = newPassword
return await this.userRepository.save(entity)
}
}

View File

@ -72,6 +72,11 @@
consola "^2.3.0"
node-fetch "^2.3.0"
"@types/bcrypt@^3.0.0":
version "3.0.0"
resolved "https://registry.npm.taobao.org/@types/bcrypt/download/@types/bcrypt-3.0.0.tgz#851489a9065a067cb7f3c9cbe4ce9bed8bba0876"
integrity sha1-hRSJqQZaBny388nL5M6b7Yu6CHY=
"@types/body-parser@*":
version "1.17.0"
resolved "https://registry.npm.taobao.org/@types/body-parser/download/@types/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c"
@ -612,6 +617,14 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
bcrypt@^3.0.6:
version "3.0.6"
resolved "https://registry.npm.taobao.org/bcrypt/download/bcrypt-3.0.6.tgz#f607846df62d27e60d5e795612c4f67d70206eb2"
integrity sha1-9geEbfYtJ+YNXnlWEsT2fXAgbrI=
dependencies:
nan "2.13.2"
node-pre-gyp "0.12.0"
bignumber.js@7.2.1:
version "7.2.1"
resolved "https://registry.npm.taobao.org/bignumber.js/download/bignumber.js-7.2.1.tgz#80c048759d826800807c4bfd521e50edbba57a5f"
@ -837,6 +850,11 @@ ci-info@^1.5.0:
resolved "https://registry.npm.taobao.org/ci-info/download/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
integrity sha1-LKINu5zrMtRSSmgzAzE/AwSx5Jc=
class-transformer@^0.2.3:
version "0.2.3"
resolved "https://registry.npm.taobao.org/class-transformer/download/class-transformer-0.2.3.tgz#598c92ca71dcca73f91ccb875d74a3847ccfa32d"
integrity sha1-WYySynHcynP5HMuHXXSjhHzPoy0=
class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@ -3371,6 +3389,11 @@ mz@^2.4.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@2.13.2:
version "2.13.2"
resolved "https://registry.npm.taobao.org/nan/download/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
integrity sha1-9R3Hrma6fV1V4ebU2AkugCya7+c=
nan@^2.12.1:
version "2.14.0"
resolved "https://registry.npm.taobao.org/nan/download/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
@ -3448,7 +3471,7 @@ node-notifier@^5.2.1:
shellwords "^0.1.1"
which "^1.3.0"
node-pre-gyp@^0.12.0:
node-pre-gyp@0.12.0, node-pre-gyp@^0.12.0:
version "0.12.0"
resolved "https://registry.npm.taobao.org/node-pre-gyp/download/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
integrity sha1-ObpLsUOdoDApX4meO1ILd4V2YUk=