251121:1700 Backend T3 wait testt

This commit is contained in:
admin
2025-11-21 17:16:40 +07:00
parent 58cee2d007
commit bf0308e350
27 changed files with 6651 additions and 196 deletions
@@ -0,0 +1,24 @@
import { IsInt, IsNotEmpty, IsOptional, ValidateIf } from 'class-validator';
export class AssignRoleDto {
@IsInt()
@IsNotEmpty()
userId!: number;
@IsInt()
@IsNotEmpty()
roleId!: number;
// Scope (ต้องส่งมาอย่างน้อย 1 อัน หรือไม่ส่งเลยถ้าเป็น Global)
@IsInt()
@IsOptional()
organizationId?: number;
@IsInt()
@IsOptional()
projectId?: number;
@IsInt()
@IsOptional()
contractId?: number;
}
@@ -0,0 +1,42 @@
import {
Entity,
Column,
PrimaryGeneratedColumn,
ManyToOne,
JoinColumn,
CreateDateColumn,
} from 'typeorm';
import { User } from './user.entity.js';
// Import Role, Org, Project, Contract entities...
@Entity('user_assignments')
export class UserAssignment {
@PrimaryGeneratedColumn()
id!: number;
@Column({ name: 'user_id' })
userId!: number;
@Column({ name: 'role_id' })
roleId!: number;
@Column({ name: 'organization_id', nullable: true })
organizationId?: number;
@Column({ name: 'project_id', nullable: true })
projectId?: number;
@Column({ name: 'contract_id', nullable: true })
contractId?: number;
@Column({ name: 'assigned_by_user_id', nullable: true })
assignedByUserId?: number;
@CreateDateColumn({ name: 'assigned_at' })
assignedAt!: Date;
// Relation กลับไปหา User (เจ้าของสิทธิ์)
@ManyToOne(() => User)
@JoinColumn({ name: 'user_id' })
user?: User;
}
@@ -0,0 +1,38 @@
import { Injectable, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserAssignment } from './entities/user-assignment.entity.js'; // ต้องไปสร้าง Entity นี้ก่อน (ดูข้อ 3)
import { AssignRoleDto } from './dto/assign-role.dto.js';
import { User } from './entities/user.entity.js';
@Injectable()
export class UserAssignmentService {
constructor(
@InjectRepository(UserAssignment)
private assignmentRepo: Repository<UserAssignment>,
) {}
async assignRole(dto: AssignRoleDto, assigner: User) {
// Validation: ตรวจสอบกฎเหล็ก (เลือกได้แค่ Scope เดียว)
const scopes = [dto.organizationId, dto.projectId, dto.contractId].filter(
(v) => v != null,
);
if (scopes.length > 1) {
throw new BadRequestException(
'Cannot assign multiple scopes at once. Choose one of Org, Project, or Contract.',
);
}
// สร้าง Assignment
const assignment = this.assignmentRepo.create({
userId: dto.userId,
roleId: dto.roleId,
organizationId: dto.organizationId,
projectId: dto.projectId,
contractId: dto.contractId,
assignedByUserId: assigner.user_id, // เก็บ Log ว่าใครเป็นคนให้สิทธิ์
});
return this.assignmentRepo.save(assignment);
}
}
+25 -9
View File
@@ -8,40 +8,48 @@ import {
Delete,
UseGuards,
ParseIntPipe,
Request, // <--- อย่าลืม Import Request
} from '@nestjs/common';
import { UserService } from './user.service.js';
import { CreateUserDto } from './dto/create-user.dto.js';
import { UpdateUserDto } from './dto/update-user.dto.js';
import { AssignRoleDto } from './dto/assign-role.dto.js'; // <--- Import DTO
import { UserAssignmentService } from './user-assignment.service.js'; // <--- Import Service ใหม่
import { JwtAuthGuard } from '../../common/auth/jwt-auth.guard.js';
import { RequirePermission } from '../../common/decorators/require-permission.decorator.js';
import { RbacGuard } from '../../common/auth/rbac.guard.js';
import { RequirePermission } from '../../common/decorators/require-permission.decorator.js';
@Controller('users')
@UseGuards(JwtAuthGuard, RbacGuard) // 🔒 เพิ่ม RbacGuard ต่อท้าย) // 🔒 บังคับ Login ทุก Endpoints ในนี้
@UseGuards(JwtAuthGuard, RbacGuard)
export class UserController {
constructor(private readonly userService: UserService) {}
constructor(
private readonly userService: UserService,
private readonly assignmentService: UserAssignmentService, // <--- ✅ Inject Service เข้ามา
) {}
// --- User CRUD ---
// 1. สร้างผู้ใช้ใหม่
@Post()
@RequirePermission('user.create') // 🔒 ต้องมีสิทธิ์ user.create ถึงจะเข้าได้
@RequirePermission('user.create')
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
// 2. ดูรายชื่อผู้ใช้ทั้งหมด
@Get()
@RequirePermission('user.view')
findAll() {
return this.userService.findAll();
}
// 3. ดูข้อมูลผู้ใช้รายคน (ตาม ID)
@Get(':id')
@RequirePermission('user.view')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.userService.findOne(id);
}
// 4. แก้ไขข้อมูลผู้ใช้
@Patch(':id')
@RequirePermission('user.edit')
update(
@Param('id', ParseIntPipe) id: number,
@Body() updateUserDto: UpdateUserDto,
@@ -49,9 +57,17 @@ export class UserController {
return this.userService.update(id, updateUserDto);
}
// 5. ลบผู้ใช้ (Soft Delete)
@Delete(':id')
@RequirePermission('user.delete')
remove(@Param('id', ParseIntPipe) id: number) {
return this.userService.remove(id);
}
// --- Role Assignment ---
@Post('assign-role') // <--- ✅ ต้องมี @ เสมอครับ
@RequirePermission('permission.assign')
assignRole(@Body() dto: AssignRoleDto, @Request() req: any) {
return this.assignmentService.assignRole(dto, req.user);
}
}
+14 -4
View File
@@ -3,12 +3,22 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { UserService } from './user.service.js';
import { UserController } from './user.controller.js'; // 1. Import Controller
import { User } from './entities/user.entity.js';
import { UserAssignmentService } from './user-assignment.service.js';
import { UserAssignment } from './entities/user-assignment.entity.js';
@Module({
imports: [TypeOrmModule.forFeature([User])], // จดทะเบียน Entity
// 2. เพิ่มบรรทัดนี้ เพื่อบอก NestJS ว่ามี Controller นี้อยู่
imports: [
// 3. ลงทะเบียน Entity ทั้ง User และ UserAssignment
TypeOrmModule.forFeature([User, UserAssignment]),
], // 2. เพิ่มบรรทัดนี้ เพื่อบอก NestJS ว่ามี Controller นี้อยู่
controllers: [UserController],
providers: [UserService],
exports: [UserService], // Export ให้ AuthModule เรียกใช้ได้
providers: [
UserService,
UserAssignmentService, // <--- 4. ลงทะเบียน Service เป็น Provider
],
exports: [
UserService,
UserAssignmentService, // <--- 5. Export เผื่อที่อื่นใช้
], // Export ให้ AuthModule เรียกใช้ได้
})
export class UserModule {}