feat: Add login
This commit is contained in:
2
backend-api/.gitignore
vendored
2
backend-api/.gitignore
vendored
@@ -6,6 +6,8 @@ config.serverless.yml
|
|||||||
vanillameta
|
vanillameta
|
||||||
bigquery-key.json
|
bigquery-key.json
|
||||||
test-connect-info.json
|
test-connect-info.json
|
||||||
|
cert.pem
|
||||||
|
key.pem
|
||||||
.
|
.
|
||||||
# compiled output
|
# compiled output
|
||||||
/dist
|
/dist
|
||||||
|
|||||||
100
backend-api/package-lock.json
generated
100
backend-api/package-lock.json
generated
@@ -2822,11 +2822,25 @@
|
|||||||
"uuid": "9.0.0"
|
"uuid": "9.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@nestjs/jwt": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZsXGY/wMYKzEhymw2+dxiwrHTRKIKrGszx6r2EjQqNLypdXMQu0QrujwZJ8k3+XQV4snmuJwwNakQoA2ILfq8w==",
|
||||||
|
"requires": {
|
||||||
|
"@types/jsonwebtoken": "8.5.8",
|
||||||
|
"jsonwebtoken": "8.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@nestjs/mapped-types": {
|
"@nestjs/mapped-types": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-1.1.0.tgz",
|
||||||
"integrity": "sha512-+2kSly4P1QI+9eGt+/uGyPdEG1hVz7nbpqPHWZVYgoqz8eOHljpXPag+UCVRw9zo2XCu4sgNUIGe8Uk0+OvUQg=="
|
"integrity": "sha512-+2kSly4P1QI+9eGt+/uGyPdEG1hVz7nbpqPHWZVYgoqz8eOHljpXPag+UCVRw9zo2XCu4sgNUIGe8Uk0+OvUQg=="
|
||||||
},
|
},
|
||||||
|
"@nestjs/passport": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-Gnh8n1wzFPOLSS/94X1sUP4IRAoXTgG4odl7/AO5h+uwscEGXxJFercrZfqdAwkWhqkKWbsntM3j5mRy/6ZQDA=="
|
||||||
|
},
|
||||||
"@nestjs/platform-express": {
|
"@nestjs/platform-express": {
|
||||||
"version": "9.1.1",
|
"version": "9.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.1.1.tgz",
|
||||||
@@ -4052,6 +4066,14 @@
|
|||||||
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/jsonwebtoken": {
|
||||||
|
"version": "8.5.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz",
|
||||||
|
"integrity": "sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/keyv": {
|
"@types/keyv": {
|
||||||
"version": "3.1.4",
|
"version": "3.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
|
||||||
@@ -4122,6 +4144,47 @@
|
|||||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/passport": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-pz1cx9ptZvozyGKKKIPLcVDVHwae4hrH5d6g5J+DkMRRjR3cVETb4jMabhXAUbg3Ov7T22nFHEgaK2jj+5CBpw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/express": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/passport-jwt": {
|
||||||
|
"version": "3.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-3.0.7.tgz",
|
||||||
|
"integrity": "sha512-qRQ4qlww1Yhs3IaioDKrsDNmKy6gLDLgFsGwpCnc2YqWovO2Oxu9yCQdWHMJafQ7UIuOba4C4/TNXcGkQfEjlQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/jsonwebtoken": "*",
|
||||||
|
"@types/passport-strategy": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/passport-local": {
|
||||||
|
"version": "1.0.34",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.34.tgz",
|
||||||
|
"integrity": "sha512-PSc07UdYx+jhadySxxIYWuv6sAnY5e+gesn/5lkPKfBeGuIYn9OPR+AAEDq73VRUh6NBTpvE/iPE62rzZUslog==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/passport": "*",
|
||||||
|
"@types/passport-strategy": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/passport-strategy": {
|
||||||
|
"version": "0.2.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz",
|
||||||
|
"integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/passport": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/prettier": {
|
"@types/prettier": {
|
||||||
"version": "2.7.0",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz",
|
||||||
@@ -13676,6 +13739,38 @@
|
|||||||
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
|
||||||
"integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw=="
|
"integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw=="
|
||||||
},
|
},
|
||||||
|
"passport": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==",
|
||||||
|
"requires": {
|
||||||
|
"passport-strategy": "1.x.x",
|
||||||
|
"pause": "0.0.1",
|
||||||
|
"utils-merge": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"passport-jwt": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==",
|
||||||
|
"requires": {
|
||||||
|
"jsonwebtoken": "^8.2.0",
|
||||||
|
"passport-strategy": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"passport-local": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==",
|
||||||
|
"requires": {
|
||||||
|
"passport-strategy": "1.x.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"passport-strategy": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA=="
|
||||||
|
},
|
||||||
"path-browserify": {
|
"path-browserify": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
|
||||||
@@ -13802,6 +13897,11 @@
|
|||||||
"integrity": "sha512-TX+cz8Jk+ta7IvRy2FAej8rdlbrP0+uBIkP/5DTODez/AuL/vSb30KuAdDxGVREXzn8QfAiu5mJYJ1XjbOhEPA==",
|
"integrity": "sha512-TX+cz8Jk+ta7IvRy2FAej8rdlbrP0+uBIkP/5DTODez/AuL/vSb30KuAdDxGVREXzn8QfAiu5mJYJ1XjbOhEPA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"pause": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
||||||
|
},
|
||||||
"pause-stream": {
|
"pause-stream": {
|
||||||
"version": "0.0.11",
|
"version": "0.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
|
||||||
|
|||||||
@@ -29,7 +29,9 @@
|
|||||||
"@nestjs/common": "^9.0.0",
|
"@nestjs/common": "^9.0.0",
|
||||||
"@nestjs/config": "^2.2.0",
|
"@nestjs/config": "^2.2.0",
|
||||||
"@nestjs/core": "^9.0.0",
|
"@nestjs/core": "^9.0.0",
|
||||||
|
"@nestjs/jwt": "^9.0.0",
|
||||||
"@nestjs/mapped-types": "*",
|
"@nestjs/mapped-types": "*",
|
||||||
|
"@nestjs/passport": "^9.0.0",
|
||||||
"@nestjs/platform-express": "^9.0.0",
|
"@nestjs/platform-express": "^9.0.0",
|
||||||
"@nestjs/swagger": "^6.1.2",
|
"@nestjs/swagger": "^6.1.2",
|
||||||
"@nestjs/typeorm": "^9.0.1",
|
"@nestjs/typeorm": "^9.0.1",
|
||||||
@@ -56,6 +58,9 @@
|
|||||||
"nest-winston": "^1.7.0",
|
"nest-winston": "^1.7.0",
|
||||||
"odbc": "^2.4.6",
|
"odbc": "^2.4.6",
|
||||||
"oracledb": "^5.5.0",
|
"oracledb": "^5.5.0",
|
||||||
|
"passport": "^0.6.0",
|
||||||
|
"passport-jwt": "^4.0.0",
|
||||||
|
"passport-local": "^1.0.0",
|
||||||
"pg": "^8.8.0",
|
"pg": "^8.8.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
@@ -76,6 +81,8 @@
|
|||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
"@types/jest": "28.1.8",
|
"@types/jest": "28.1.8",
|
||||||
"@types/node": "^16.0.0",
|
"@types/node": "^16.0.0",
|
||||||
|
"@types/passport-jwt": "^3.0.7",
|
||||||
|
"@types/passport-local": "^1.0.34",
|
||||||
"@types/supertest": "^2.0.11",
|
"@types/supertest": "^2.0.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||||
"@typescript-eslint/parser": "^5.0.0",
|
"@typescript-eslint/parser": "^5.0.0",
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import { TemplateModule } from './template/template.module';
|
|||||||
import { CommonModule } from './common/common.module';
|
import { CommonModule } from './common/common.module';
|
||||||
import { ComponentModule } from './component/component.module';
|
import { ComponentModule } from './component/component.module';
|
||||||
import { ConnectionModule } from './connection/connection.module';
|
import { ConnectionModule } from './connection/connection.module';
|
||||||
|
import { UserModule } from './user/user.module';
|
||||||
|
import { AuthModule } from './auth/auth.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -39,6 +41,9 @@ import { ConnectionModule } from './connection/connection.module';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
ComponentModule,
|
ComponentModule,
|
||||||
ConnectionModule,
|
ConnectionModule,
|
||||||
|
UserModule,
|
||||||
|
AuthModule,
|
||||||
|
UserModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
|
|||||||
22
backend-api/src/auth/auth.module.ts
Normal file
22
backend-api/src/auth/auth.module.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { UserModule } from 'src/user/user.module';
|
||||||
|
import { AuthService } from './auth.service';
|
||||||
|
import { JwtModule, JwtService } from '@nestjs/jwt';
|
||||||
|
import { PassportModule } from '@nestjs/passport';
|
||||||
|
import { JwtStrategy } from './strategies/jwt.strategy';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { User } from '../user/entities/user.entity.js';
|
||||||
|
import { UserService } from 'src/user/user.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
TypeOrmModule.forFeature([User]),
|
||||||
|
PassportModule,
|
||||||
|
JwtModule.register({
|
||||||
|
secret: process.env.JWT_ACCESS_SECRET,
|
||||||
|
signOptions: { expiresIn: '30s'}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
providers: [AuthService]
|
||||||
|
})
|
||||||
|
export class AuthModule {}
|
||||||
18
backend-api/src/auth/auth.service.spec.ts
Normal file
18
backend-api/src/auth/auth.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { AuthService } from './auth.service';
|
||||||
|
|
||||||
|
describe('AuthService', () => {
|
||||||
|
let service: AuthService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [AuthService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<AuthService>(AuthService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
42
backend-api/src/auth/auth.service.ts
Normal file
42
backend-api/src/auth/auth.service.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
import { UserService } from 'src/user/user.service';
|
||||||
|
import { NestFactory } from '@nestjs/core';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { User } from 'src/user/entities/user.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuthService {
|
||||||
|
constructor(
|
||||||
|
private jwtService: JwtService,
|
||||||
|
@InjectRepository(User) private readonly userRepository: Repository<User> ){}
|
||||||
|
|
||||||
|
async generateAccessToken(email: string) {
|
||||||
|
console.log(email)
|
||||||
|
const accesstoken = await this.jwtService.sign({email: email}, {
|
||||||
|
secret: process.env.ACCESS_SECRET,
|
||||||
|
expiresIn: `30s`
|
||||||
|
})
|
||||||
|
return accesstoken
|
||||||
|
// accesstoken이 없을때
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateRefreshToken(email: string) {
|
||||||
|
const refreshtoken = await this.jwtService.sign({email: email}, { secret: process.env.REFRESH_SECRET, expiresIn: "3600s" })
|
||||||
|
return refreshtoken
|
||||||
|
// accesstoken이 없을때
|
||||||
|
}
|
||||||
|
|
||||||
|
async setRefreshKey(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async validateUser(email: string, pass: string) {
|
||||||
|
const user = await this.userRepository.findOne({ where: { email: email } });
|
||||||
|
if (user && user.password === pass) {
|
||||||
|
delete user.password;
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
backend-api/src/auth/guards/jwt-auth.guard.ts
Normal file
5
backend-api/src/auth/guards/jwt-auth.guard.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class JwtAuthGuard extends AuthGuard('jwt') {}
|
||||||
19
backend-api/src/auth/strategies/jwt.strategy.ts
Normal file
19
backend-api/src/auth/strategies/jwt.strategy.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PassportStrategy } from '@nestjs/passport';
|
||||||
|
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||||
|
ignoreExpiration: false,
|
||||||
|
secretOrKey: process.env.JWT_ACCESS_SECRET
|
||||||
|
});
|
||||||
|
console.log(process.env.JWT_ACCESS_SCRET)
|
||||||
|
}
|
||||||
|
|
||||||
|
async validate(payload: any) {
|
||||||
|
return { userId: payload.sub, username: payload.username };
|
||||||
|
}
|
||||||
|
}
|
||||||
16
backend-api/src/user/dto/create-user.dto.ts
Normal file
16
backend-api/src/user/dto/create-user.dto.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class CreateUserDto {
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
password: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
4
backend-api/src/user/dto/update-user.dto.ts
Normal file
4
backend-api/src/user/dto/update-user.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { PartialType } from '@nestjs/swagger';
|
||||||
|
import { CreateUserDto } from './create-user.dto';
|
||||||
|
|
||||||
|
export class UpdateUserDto extends PartialType(CreateUserDto) {}
|
||||||
21
backend-api/src/user/entities/user.entity.ts
Normal file
21
backend-api/src/user/entities/user.entity.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { IsNotEmpty, IsOptional } from 'class-validator';
|
||||||
|
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn} from 'typeorm';
|
||||||
|
import { BaseEntity } from '../../common/entities/base.entity';
|
||||||
|
@Entity()
|
||||||
|
export class User extends BaseEntity{
|
||||||
|
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@Column()
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@Column()
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@Column()
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
20
backend-api/src/user/user.controller.spec.ts
Normal file
20
backend-api/src/user/user.controller.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { UserController } from './user.controller';
|
||||||
|
import { UserService } from './user.service';
|
||||||
|
|
||||||
|
describe('UserController', () => {
|
||||||
|
let controller: UserController;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [UserController],
|
||||||
|
providers: [UserService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<UserController>(UserController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
64
backend-api/src/user/user.controller.ts
Normal file
64
backend-api/src/user/user.controller.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards, UsePipes, ValidationPipe, Res } from '@nestjs/common';
|
||||||
|
import { UserService } from './user.service';
|
||||||
|
import { CreateUserDto } from './dto/create-user.dto';
|
||||||
|
import { UpdateUserDto } from './dto/update-user.dto';
|
||||||
|
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
|
||||||
|
import { AuthService } from 'src/auth/auth.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Controller('user')
|
||||||
|
export class UserController {
|
||||||
|
constructor( private readonly userService: UserService,
|
||||||
|
private authService: AuthService) {}
|
||||||
|
|
||||||
|
|
||||||
|
@Post('signin')
|
||||||
|
async login(@Res() res, @Body() loginDto: UpdateUserDto){
|
||||||
|
|
||||||
|
const findUser = await this.userService.signin(loginDto)
|
||||||
|
const accessToken = await this.authService.generateAccessToken( findUser.email );
|
||||||
|
const refreshToken = await this.authService.generateRefreshToken( findUser.email );
|
||||||
|
|
||||||
|
res.cookie('jwt_ac', accessToken, {
|
||||||
|
httpOnly: true,
|
||||||
|
saemSite: 'none',
|
||||||
|
secure: true
|
||||||
|
});
|
||||||
|
res.cookie('jwt_re', refreshToken, {
|
||||||
|
httpOnly: true,
|
||||||
|
saemSite: 'none',
|
||||||
|
secure: true
|
||||||
|
})
|
||||||
|
return res.status(201).send('ok')
|
||||||
|
}
|
||||||
|
|
||||||
|
@UsePipes(ValidationPipe)
|
||||||
|
@Post('signup')
|
||||||
|
create(@Body() createUserDto: CreateUserDto) {
|
||||||
|
return this.userService.create(createUserDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Get('userinfo/:email')
|
||||||
|
findOne(@Param('email') email: string) {
|
||||||
|
return this.userService.findOne(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Patch('change-password')
|
||||||
|
updatePassword(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
|
||||||
|
return this.userService.updatePassword(+id, updateUserDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Patch('change-username')
|
||||||
|
updateUsername(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
|
||||||
|
return this.userService.updateUsername(+id, updateUserDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Delete('delete/:id')
|
||||||
|
deleteUser(@Param('id') id: string) {
|
||||||
|
return this.userService.deleteUser(+id);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
backend-api/src/user/user.module.ts
Normal file
15
backend-api/src/user/user.module.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { UserService } from './user.service';
|
||||||
|
import { UserController } from './user.controller';
|
||||||
|
import { User } from './entities/user.entity.js';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { AuthService } from 'src/auth/auth.service';
|
||||||
|
import { AuthModule } from 'src/auth/auth.module';
|
||||||
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [TypeOrmModule.forFeature([User]), AuthModule, JwtModule],
|
||||||
|
controllers: [UserController],
|
||||||
|
providers: [UserService, AuthService]
|
||||||
|
})
|
||||||
|
export class UserModule {}
|
||||||
18
backend-api/src/user/user.service.spec.ts
Normal file
18
backend-api/src/user/user.service.spec.ts
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
86
backend-api/src/user/user.service.ts
Normal file
86
backend-api/src/user/user.service.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { AuthService } from '../auth/auth.service.js';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { CreateUserDto } from './dto/create-user.dto';
|
||||||
|
import { UpdateUserDto } from './dto/update-user.dto';
|
||||||
|
import { User } from './entities/user.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserService {
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(User) private readonly userRepository: Repository<User>,
|
||||||
|
private authService: AuthService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async signin( loginDto: UpdateUserDto ) {
|
||||||
|
const { email, password } = loginDto;
|
||||||
|
const findUser = await this.authService.validateUser(email, password);
|
||||||
|
if (!findUser) {
|
||||||
|
throw new UnauthorizedException(`No exist user ${email}`);
|
||||||
|
}
|
||||||
|
return findUser
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async create(createUserDto: CreateUserDto) {
|
||||||
|
const userInfo = await this.userRepository.findOne({
|
||||||
|
where: { email: createUserDto.email }
|
||||||
|
});
|
||||||
|
if(!userInfo){
|
||||||
|
const { email, password, username } = createUserDto;
|
||||||
|
await this.userRepository.save({
|
||||||
|
email: email,
|
||||||
|
password: password,
|
||||||
|
user_name: username
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return 'This action adds a new user';
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(email: string) {
|
||||||
|
const userData = await this.userRepository.findOne({
|
||||||
|
where: { email: email }
|
||||||
|
});
|
||||||
|
if(!userData){
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
delete userData.password;
|
||||||
|
return userData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updatePassword(id: number, updateUserDto: UpdateUserDto) {
|
||||||
|
const updateData = await this.userRepository.findOne({ where: { id: id }});
|
||||||
|
if(!updateData){
|
||||||
|
return 'not exist user';
|
||||||
|
} else {
|
||||||
|
updateData.password = String(updateUserDto.password);
|
||||||
|
await this.userRepository.save(updateData)
|
||||||
|
return `This action update_password a #${id} user`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateUsername(id: number, updateUserDto: UpdateUserDto) {
|
||||||
|
const updateData = await this.userRepository.findOne({ where: { id: id }});
|
||||||
|
if(!updateData){
|
||||||
|
return 'not exist user';
|
||||||
|
} else {
|
||||||
|
updateData.username = String(updateUserDto.username);
|
||||||
|
await this.userRepository.save(updateData)
|
||||||
|
return `This action update_name a #${id} user`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteUser(id: number) {
|
||||||
|
const findUser = await this.userRepository.findOne({
|
||||||
|
where: { id: id }
|
||||||
|
});
|
||||||
|
if(!findUser){
|
||||||
|
return 'not exist user'
|
||||||
|
} else {
|
||||||
|
await this.userRepository.delete(findUser.id)
|
||||||
|
return `This action removes a #${id} user`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ export function getTestMysqlModule(): DynamicModule {
|
|||||||
autoLoadEntities: true,
|
autoLoadEntities: true,
|
||||||
entities: [entityUrl],
|
entities: [entityUrl],
|
||||||
synchronize: false,
|
synchronize: false,
|
||||||
logging: process.env.NODE_ENV == 'dev',
|
logging: true,
|
||||||
retryAttempts: 1,
|
retryAttempts: 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user