Spaces:
Sleeping
Sleeping
Merge pull request #28 from PBL6-team-CATS/revert-27-feature/update-user
Browse files- backend/src/entities/role.entity.ts +1 -1
- backend/src/entities/user.entity.ts +3 -2
- backend/src/migrations/1729952137958-Change-role-id-string-default.ts +0 -20
- backend/src/modules/authentication/authentication.module.ts +1 -3
- backend/src/modules/authentication/authentication.service.ts +4 -8
- backend/src/modules/authentication/rbac-policy.ts +9 -0
- backend/src/modules/user/dto/update-user-dto.ts +0 -31
- backend/src/modules/user/user.controller.ts +1 -9
- backend/src/modules/user/user.module.ts +1 -16
- backend/src/modules/user/user.service.ts +2 -36
- backend/src/validate/validate.service.spec.ts +0 -18
- backend/src/validate/validate.service.ts +0 -25
backend/src/entities/role.entity.ts
CHANGED
@@ -8,7 +8,7 @@ import{
|
|
8 |
@Entity('role')
|
9 |
export class RoleEntity extends BaseEntity{
|
10 |
@PrimaryGeneratedColumn('uuid')
|
11 |
-
id:
|
12 |
|
13 |
@Column({ nullable: false})
|
14 |
role_name: string;
|
|
|
8 |
@Entity('role')
|
9 |
export class RoleEntity extends BaseEntity{
|
10 |
@PrimaryGeneratedColumn('uuid')
|
11 |
+
id: number;
|
12 |
|
13 |
@Column({ nullable: false})
|
14 |
role_name: string;
|
backend/src/entities/user.entity.ts
CHANGED
@@ -34,8 +34,9 @@ export class UserEntity extends BaseEntity {
|
|
34 |
@Column({ nullable: true, unique: true })
|
35 |
email: string;
|
36 |
|
37 |
-
@
|
38 |
-
|
|
|
39 |
|
40 |
@Column()
|
41 |
hash_password: string;
|
|
|
34 |
@Column({ nullable: true, unique: true })
|
35 |
email: string;
|
36 |
|
37 |
+
@IsOptional()
|
38 |
+
@Column({ nullable: true })
|
39 |
+
role_id: number;
|
40 |
|
41 |
@Column()
|
42 |
hash_password: string;
|
backend/src/migrations/1729952137958-Change-role-id-string-default.ts
DELETED
@@ -1,20 +0,0 @@
|
|
1 |
-
import { MigrationInterface, QueryRunner } from "typeorm";
|
2 |
-
|
3 |
-
export class ChangeRoleIdStringDefault1729952137958 implements MigrationInterface {
|
4 |
-
name = 'ChangeRoleIdStringDefault1729952137958'
|
5 |
-
|
6 |
-
public async up(queryRunner: QueryRunner): Promise<void> {
|
7 |
-
await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "FK_a2cecd1a3531c0b041e29ba46e1"`);
|
8 |
-
await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "role_id" SET NOT NULL`);
|
9 |
-
await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "role_id" SET DEFAULT 'f3750930-48ab-4c30-8681-d50e68e2bda7'`);
|
10 |
-
await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "FK_a2cecd1a3531c0b041e29ba46e1" FOREIGN KEY ("role_id") REFERENCES "role"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
11 |
-
}
|
12 |
-
|
13 |
-
public async down(queryRunner: QueryRunner): Promise<void> {
|
14 |
-
await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "FK_a2cecd1a3531c0b041e29ba46e1"`);
|
15 |
-
await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "role_id" DROP DEFAULT`);
|
16 |
-
await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "role_id" DROP NOT NULL`);
|
17 |
-
await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "FK_a2cecd1a3531c0b041e29ba46e1" FOREIGN KEY ("role_id") REFERENCES "role"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
18 |
-
}
|
19 |
-
|
20 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/modules/authentication/authentication.module.ts
CHANGED
@@ -7,7 +7,6 @@ import { AuthenticationGuard } from './authentication.guard.js';
|
|
7 |
import { APP_GUARD } from '@nestjs/core';
|
8 |
import { ConfigModule, ConfigService } from '@nestjs/config';
|
9 |
import { RolesGuard } from './authorization/roles.guard.js';
|
10 |
-
import { ValidateService } from '../../validate/validate.service.js';
|
11 |
@Module({
|
12 |
imports: [
|
13 |
UserModule,
|
@@ -29,8 +28,7 @@ import { ValidateService } from '../../validate/validate.service.js';
|
|
29 |
{
|
30 |
provide: APP_GUARD,
|
31 |
useClass: RolesGuard,
|
32 |
-
}
|
33 |
-
ValidateService
|
34 |
],
|
35 |
controllers: [AuthenticationController],
|
36 |
exports: [AuthenticationService],
|
|
|
7 |
import { APP_GUARD } from '@nestjs/core';
|
8 |
import { ConfigModule, ConfigService } from '@nestjs/config';
|
9 |
import { RolesGuard } from './authorization/roles.guard.js';
|
|
|
10 |
@Module({
|
11 |
imports: [
|
12 |
UserModule,
|
|
|
28 |
{
|
29 |
provide: APP_GUARD,
|
30 |
useClass: RolesGuard,
|
31 |
+
}
|
|
|
32 |
],
|
33 |
controllers: [AuthenticationController],
|
34 |
exports: [AuthenticationService],
|
backend/src/modules/authentication/authentication.service.ts
CHANGED
@@ -4,13 +4,11 @@ import * as bcrypt from 'bcrypt';
|
|
4 |
import { JwtService } from '@nestjs/jwt';
|
5 |
import { SignUpDto } from './dto/sign-up.dto.js';
|
6 |
import { UserEntity } from '../../entities/user.entity.js';
|
7 |
-
import { ValidateService } from '../../validate/validate.service.js';
|
8 |
@Injectable()
|
9 |
export class AuthenticationService {
|
10 |
constructor(
|
11 |
private usersService: UserService,
|
12 |
private jwtService: JwtService,
|
13 |
-
private validatService: ValidateService
|
14 |
) {}
|
15 |
|
16 |
async signIn(
|
@@ -22,12 +20,10 @@ export class AuthenticationService {
|
|
22 |
user = await this.usersService.findOneByField('email', username);
|
23 |
else
|
24 |
user = await this.usersService.findOneByField('phone_number', username);
|
25 |
-
|
26 |
-
console.log(compare);
|
27 |
-
if (( !user || !compare )) {
|
28 |
throw new UnauthorizedException();
|
29 |
}
|
30 |
-
const payload = { sub: user.id, username: user.
|
31 |
return {
|
32 |
access_token: await this.jwtService.signAsync(payload),
|
33 |
};
|
@@ -43,8 +39,8 @@ export class AuthenticationService {
|
|
43 |
password
|
44 |
} = signUpDto
|
45 |
|
46 |
-
await this.
|
47 |
-
await this.
|
48 |
const hash_password = await bcrypt.hash(password, 10)
|
49 |
|
50 |
const user = await this.usersService.create({
|
|
|
4 |
import { JwtService } from '@nestjs/jwt';
|
5 |
import { SignUpDto } from './dto/sign-up.dto.js';
|
6 |
import { UserEntity } from '../../entities/user.entity.js';
|
|
|
7 |
@Injectable()
|
8 |
export class AuthenticationService {
|
9 |
constructor(
|
10 |
private usersService: UserService,
|
11 |
private jwtService: JwtService,
|
|
|
12 |
) {}
|
13 |
|
14 |
async signIn(
|
|
|
20 |
user = await this.usersService.findOneByField('email', username);
|
21 |
else
|
22 |
user = await this.usersService.findOneByField('phone_number', username);
|
23 |
+
if (!user || (await !bcrypt.compare(pass, user.hash_password))) {
|
|
|
|
|
24 |
throw new UnauthorizedException();
|
25 |
}
|
26 |
+
const payload = { sub: user.id, username: user.id, roles: user.role.role_name};
|
27 |
return {
|
28 |
access_token: await this.jwtService.signAsync(payload),
|
29 |
};
|
|
|
39 |
password
|
40 |
} = signUpDto
|
41 |
|
42 |
+
await this.checkExistField('email', email);
|
43 |
+
await this.checkExistField('phone_number', phone_number)
|
44 |
const hash_password = await bcrypt.hash(password, 10)
|
45 |
|
46 |
const user = await this.usersService.create({
|
backend/src/modules/authentication/rbac-policy.ts
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { RolesBuilder } from 'nest-access-control';
|
2 |
+
import { Role } from './enums';
|
3 |
+
|
4 |
+
export const RBAC_POLICY: RolesBuilder = new RolesBuilder();
|
5 |
+
|
6 |
+
// prettier-ignore
|
7 |
+
RBAC_POLICY
|
8 |
+
.grant(Role.ADMIN)
|
9 |
+
.read()
|
backend/src/modules/user/dto/update-user-dto.ts
DELETED
@@ -1,31 +0,0 @@
|
|
1 |
-
import { IsEmail, IsMobilePhone, IsOptional, IsString } from "class-validator";
|
2 |
-
import { Column } from "typeorm";
|
3 |
-
|
4 |
-
export class UpdateUserDto{
|
5 |
-
|
6 |
-
@IsOptional()
|
7 |
-
avatar: string;
|
8 |
-
|
9 |
-
@IsOptional()
|
10 |
-
full_name: string;
|
11 |
-
|
12 |
-
@IsOptional()
|
13 |
-
@IsMobilePhone('vi-VN')
|
14 |
-
phone_number: string;
|
15 |
-
|
16 |
-
@IsOptional()
|
17 |
-
address: string;
|
18 |
-
|
19 |
-
@IsOptional()
|
20 |
-
@IsEmail()
|
21 |
-
email: string;
|
22 |
-
|
23 |
-
@IsOptional()
|
24 |
-
role_id: string;
|
25 |
-
|
26 |
-
@IsOptional()
|
27 |
-
hash_password: string;
|
28 |
-
|
29 |
-
@IsOptional()
|
30 |
-
is_valid: boolean;
|
31 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/modules/user/user.controller.ts
CHANGED
@@ -1,7 +1,6 @@
|
|
1 |
-
import {
|
2 |
import { UserService } from './user.service.js';
|
3 |
import { UserEntity } from 'src/entities/user.entity.js';
|
4 |
-
import { UpdateUserDto } from './dto/update-user-dto.js';
|
5 |
|
6 |
@Controller('users')
|
7 |
export class UsersController {
|
@@ -13,11 +12,4 @@ export class UsersController {
|
|
13 |
): Promise<UserEntity | undefined> {
|
14 |
return this.usersService.findOne(username);
|
15 |
}
|
16 |
-
|
17 |
-
@Post('updateUser')
|
18 |
-
async updateUser(@Request() req){
|
19 |
-
const userId = req.user.sub;
|
20 |
-
const updateUserDto = req.body;
|
21 |
-
return this.usersService.updateUserById(userId, updateUserDto);
|
22 |
-
}
|
23 |
}
|
|
|
1 |
+
import { Controller, Get, Param } from '@nestjs/common';
|
2 |
import { UserService } from './user.service.js';
|
3 |
import { UserEntity } from 'src/entities/user.entity.js';
|
|
|
4 |
|
5 |
@Controller('users')
|
6 |
export class UsersController {
|
|
|
12 |
): Promise<UserEntity | undefined> {
|
13 |
return this.usersService.findOne(username);
|
14 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
}
|
backend/src/modules/user/user.module.ts
CHANGED
@@ -1,23 +1,8 @@
|
|
1 |
import { Module } from '@nestjs/common';
|
2 |
import { UserService } from './user.service.js';
|
3 |
-
import { ValidateService } from '../../validate/validate.service.js';
|
4 |
-
import { UsersController } from './user.controller.js';
|
5 |
-
import { JwtModule } from '@nestjs/jwt';
|
6 |
-
import { ConfigModule, ConfigService } from '@nestjs/config';
|
7 |
|
8 |
@Module({
|
9 |
-
|
10 |
-
JwtModule.registerAsync({
|
11 |
-
imports: [ConfigModule], // Nhập ConfigModule để sử dụng ConfigService
|
12 |
-
useFactory: async (configService: ConfigService) => ({
|
13 |
-
secret: configService.get<string>('JWT_KEY'), // Lấy giá trị từ biến môi trường
|
14 |
-
signOptions: { expiresIn: '7d' }, // Thời gian hết hạn token
|
15 |
-
}),
|
16 |
-
inject: [ConfigService], // Inject ConfigService vào factory
|
17 |
-
}),
|
18 |
-
],
|
19 |
-
controllers: [UsersController],
|
20 |
-
providers: [UserService, ValidateService],
|
21 |
exports: [UserService],
|
22 |
})
|
23 |
export class UserModule {}
|
|
|
1 |
import { Module } from '@nestjs/common';
|
2 |
import { UserService } from './user.service.js';
|
|
|
|
|
|
|
|
|
3 |
|
4 |
@Module({
|
5 |
+
providers: [UserService],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
exports: [UserService],
|
7 |
})
|
8 |
export class UserModule {}
|
backend/src/modules/user/user.service.ts
CHANGED
@@ -1,19 +1,12 @@
|
|
1 |
-
import {
|
2 |
import { UserEntity } from '../../entities/user.entity.js';
|
3 |
import { SignUpDto } from '../authentication/dto/sign-up.dto.js';
|
4 |
-
import { UpdateUserDto } from './dto/update-user-dto.js';
|
5 |
-
import { ValidateService } from '../../validate/validate.service.js';
|
6 |
-
import * as bcrypt from 'bcrypt';
|
7 |
-
import { JwtService } from '@nestjs/jwt';
|
8 |
|
9 |
export type User = any;
|
10 |
|
11 |
@Injectable()
|
12 |
export class UserService {
|
13 |
-
constructor(
|
14 |
-
private validateService: ValidateService,
|
15 |
-
private jwtService: JwtService,
|
16 |
-
) {}
|
17 |
|
18 |
async findOne(username: string): Promise<UserEntity | undefined> {
|
19 |
return UserEntity.findOne({ where: { full_name: username } });
|
@@ -38,31 +31,4 @@ export class UserService {
|
|
38 |
relations: ['role']
|
39 |
});
|
40 |
}
|
41 |
-
|
42 |
-
async updateUserById(userId: string, updateUserDto: UpdateUserDto){
|
43 |
-
|
44 |
-
await this.validateService.checkExistField('email', updateUserDto.email);
|
45 |
-
await this.validateService.checkExistField('phone_number', updateUserDto.phone_number);
|
46 |
-
|
47 |
-
const user = await UserEntity.findOne({
|
48 |
-
where: { id: userId },
|
49 |
-
relations: ['role']
|
50 |
-
});
|
51 |
-
if (!user) {
|
52 |
-
throw new NotFoundException(`User with ID ${userId} not found`);
|
53 |
-
}
|
54 |
-
|
55 |
-
Object.assign(user, updateUserDto);
|
56 |
-
if (updateUserDto.hash_password) {
|
57 |
-
const saltRounds = 10;
|
58 |
-
user.hash_password = await bcrypt.hash(updateUserDto.hash_password, saltRounds); // Mã hóa mật khẩu
|
59 |
-
}
|
60 |
-
await UserEntity.save(user);
|
61 |
-
|
62 |
-
const payload = { sub: user.id, username: user.full_name, roles: user.role.role_name };
|
63 |
-
const token = await this.jwtService.signAsync(payload)
|
64 |
-
return {
|
65 |
-
access_token: token
|
66 |
-
};
|
67 |
-
}
|
68 |
}
|
|
|
1 |
+
import { Injectable } from '@nestjs/common';
|
2 |
import { UserEntity } from '../../entities/user.entity.js';
|
3 |
import { SignUpDto } from '../authentication/dto/sign-up.dto.js';
|
|
|
|
|
|
|
|
|
4 |
|
5 |
export type User = any;
|
6 |
|
7 |
@Injectable()
|
8 |
export class UserService {
|
9 |
+
constructor() {}
|
|
|
|
|
|
|
10 |
|
11 |
async findOne(username: string): Promise<UserEntity | undefined> {
|
12 |
return UserEntity.findOne({ where: { full_name: username } });
|
|
|
31 |
relations: ['role']
|
32 |
});
|
33 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
}
|
backend/src/validate/validate.service.spec.ts
DELETED
@@ -1,18 +0,0 @@
|
|
1 |
-
import { Test, TestingModule } from '@nestjs/testing';
|
2 |
-
import { ValidateService } from './validate.service';
|
3 |
-
|
4 |
-
describe('ValidateService', () => {
|
5 |
-
let service: ValidateService;
|
6 |
-
|
7 |
-
beforeEach(async () => {
|
8 |
-
const module: TestingModule = await Test.createTestingModule({
|
9 |
-
providers: [ValidateService],
|
10 |
-
}).compile();
|
11 |
-
|
12 |
-
service = module.get<ValidateService>(ValidateService);
|
13 |
-
});
|
14 |
-
|
15 |
-
it('should be defined', () => {
|
16 |
-
expect(service).toBeDefined();
|
17 |
-
});
|
18 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/src/validate/validate.service.ts
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
// validation.service.ts
|
2 |
-
import { Injectable, ConflictException } from '@nestjs/common';
|
3 |
-
import { UserEntity } from '../entities/user.entity.js';
|
4 |
-
|
5 |
-
@Injectable()
|
6 |
-
export class ValidateService {
|
7 |
-
constructor() {}
|
8 |
-
|
9 |
-
// Kiểm tra xem giá trị của một trường có tồn tại không
|
10 |
-
async checkExistField(fieldName: string, fieldValue: any): Promise<void> {
|
11 |
-
if (fieldValue === null || fieldValue === undefined) {
|
12 |
-
return; // Nếu giá trị null hoặc undefined, không cần kiểm tra
|
13 |
-
}
|
14 |
-
|
15 |
-
// Tìm trong database theo tên và giá trị của trường
|
16 |
-
const existingUser = await UserEntity.findOne({
|
17 |
-
where: { [fieldName]: fieldValue },
|
18 |
-
relations: ['role']
|
19 |
-
});
|
20 |
-
|
21 |
-
if (existingUser) {
|
22 |
-
throw new ConflictException(`${fieldName} is already taken`);
|
23 |
-
}
|
24 |
-
}
|
25 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|