251123:2300 Update T1
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import {
|
||||
IsString,
|
||||
IsNotEmpty,
|
||||
IsInt,
|
||||
IsOptional,
|
||||
IsBoolean,
|
||||
IsObject,
|
||||
} from 'class-validator';
|
||||
|
||||
export class CreateJsonSchemaDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
schemaCode!: string; // รหัส Schema (ต้องไม่ซ้ำ เช่น 'RFA_DWG_V1')
|
||||
|
||||
@IsInt()
|
||||
@IsOptional()
|
||||
version?: number; // เวอร์ชัน (Default: 1)
|
||||
|
||||
@IsObject()
|
||||
@IsNotEmpty()
|
||||
schemaDefinition!: Record<string, any>; // โครงสร้าง JSON Schema (Standard Format)
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
isActive?: boolean; // สถานะการใช้งาน
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { IsString, IsOptional, IsBoolean, IsInt } from 'class-validator';
|
||||
import { Type, Transform } from 'class-transformer';
|
||||
|
||||
export class SearchJsonSchemaDto {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
search?: string; // ค้นหาจาก schemaCode
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => {
|
||||
if (value === 'true') return true;
|
||||
if (value === 'false') return false;
|
||||
return value;
|
||||
})
|
||||
isActive?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
page: number = 1;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
limit: number = 20;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/swagger';
|
||||
import { CreateJsonSchemaDto } from './create-json-schema.dto';
|
||||
|
||||
export class UpdateJsonSchemaDto extends PartialType(CreateJsonSchemaDto) {}
|
||||
@@ -1,25 +1,36 @@
|
||||
import { Controller, Post, Body, Param, UseGuards } from '@nestjs/common';
|
||||
import { JsonSchemaService } from './json-schema.service.js';
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard.js';
|
||||
import { RbacGuard } from '../../common/guards/rbac.guard.js';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator.js';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
|
||||
@Controller('json-schemas')
|
||||
import { JsonSchemaService } from './json-schema.service';
|
||||
// ✅ FIX: Import DTO
|
||||
import { CreateJsonSchemaDto } from './dto/create-json-schema.dto';
|
||||
// ✅ FIX: แก้ไข Path ของ Guards
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
|
||||
import { RbacGuard } from '../../common/guards/rbac.guard';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator';
|
||||
|
||||
@ApiTags('JSON Schemas') // ✅ Add Swagger Tag
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, RbacGuard)
|
||||
@Controller('json-schemas')
|
||||
export class JsonSchemaController {
|
||||
constructor(private readonly schemaService: JsonSchemaService) {}
|
||||
|
||||
@Post(':code')
|
||||
@RequirePermission('system.manage_all') // เฉพาะ Superadmin หรือผู้มีสิทธิ์จัดการ System
|
||||
create(@Param('code') code: string, @Body() definition: any) {
|
||||
return this.schemaService.createOrUpdate(code, definition);
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Create or Update JSON Schema' })
|
||||
@RequirePermission('system.manage_all') // Admin Only
|
||||
create(@Body() createDto: CreateJsonSchemaDto) {
|
||||
return this.schemaService.createOrUpdate(
|
||||
createDto.schemaCode,
|
||||
createDto.schemaDefinition,
|
||||
);
|
||||
}
|
||||
|
||||
// Endpoint สำหรับ Test Validate (Optional)
|
||||
@Post(':code/validate')
|
||||
@ApiOperation({ summary: 'Test validation against a schema' })
|
||||
@RequirePermission('document.view')
|
||||
async validate(@Param('code') code: string, @Body() data: any) {
|
||||
const isValid = await this.schemaService.validate(code, data);
|
||||
return { valid: isValid };
|
||||
return { valid: isValid, message: 'Validation passed' };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { JsonSchemaService } from './json-schema.service.js';
|
||||
import { JsonSchemaController } from './json-schema.controller.js';
|
||||
import { JsonSchema } from './entities/json-schema.entity.js';
|
||||
import { UserModule } from '../user/user.module.js'; // <--- 1. Import UserModule
|
||||
import { JsonSchemaService } from './json-schema.service';
|
||||
import { JsonSchemaController } from './json-schema.controller';
|
||||
import { JsonSchema } from './entities/json-schema.entity';
|
||||
import { UserModule } from '../user/user.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([JsonSchema]),
|
||||
UserModule, // <--- 2. ใส่ UserModule ใน imports
|
||||
],
|
||||
imports: [TypeOrmModule.forFeature([JsonSchema]), UserModule],
|
||||
controllers: [JsonSchemaController],
|
||||
providers: [JsonSchemaService],
|
||||
exports: [JsonSchemaService], // Export ให้ Module อื่นเรียกใช้ .validate()
|
||||
exports: [JsonSchemaService],
|
||||
})
|
||||
export class JsonSchemaModule {}
|
||||
|
||||
@@ -3,31 +3,32 @@ import {
|
||||
OnModuleInit,
|
||||
BadRequestException,
|
||||
NotFoundException,
|
||||
Logger,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import Ajv from 'ajv';
|
||||
import addFormats from 'ajv-formats';
|
||||
import { JsonSchema } from './entities/json-schema.entity.js';
|
||||
import { JsonSchema } from './entities/json-schema.entity'; // ลบ .js
|
||||
|
||||
@Injectable()
|
||||
export class JsonSchemaService implements OnModuleInit {
|
||||
private ajv: Ajv;
|
||||
// Cache ตัว Validator ที่ Compile แล้ว เพื่อประสิทธิภาพ
|
||||
private validators = new Map<string, any>();
|
||||
private readonly logger = new Logger(JsonSchemaService.name);
|
||||
|
||||
constructor(
|
||||
@InjectRepository(JsonSchema)
|
||||
private schemaRepo: Repository<JsonSchema>,
|
||||
) {
|
||||
// ตั้งค่า AJV
|
||||
this.ajv = new Ajv({ allErrors: true, strict: false }); // strict: false เพื่อยืดหยุ่นกับ custom keywords
|
||||
addFormats(this.ajv); // รองรับ format เช่น email, date-time
|
||||
this.ajv = new Ajv({ allErrors: true, strict: false });
|
||||
addFormats(this.ajv);
|
||||
}
|
||||
|
||||
onModuleInit() {
|
||||
// (Optional) โหลด Schema ทั้งหมดมา Cache ตอนเริ่ม App ก็ได้
|
||||
// แต่ตอนนี้ใช้วิธี Lazy Load (โหลดเมื่อใช้) ไปก่อน
|
||||
async onModuleInit() {
|
||||
// Pre-load schemas (Optional for performance)
|
||||
// const schemas = await this.schemaRepo.find({ where: { isActive: true } });
|
||||
// schemas.forEach(s => this.createValidator(s.schemaCode, s.schemaDefinition));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,7 +37,6 @@ export class JsonSchemaService implements OnModuleInit {
|
||||
async validate(schemaCode: string, data: any): Promise<boolean> {
|
||||
let validate = this.validators.get(schemaCode);
|
||||
|
||||
// ถ้ายังไม่มีใน Cache หรือต้องการตัวล่าสุด ให้ดึงจาก DB
|
||||
if (!validate) {
|
||||
const schema = await this.schemaRepo.findOne({
|
||||
where: { schemaCode, isActive: true },
|
||||
@@ -59,19 +59,21 @@ export class JsonSchemaService implements OnModuleInit {
|
||||
const valid = validate(data);
|
||||
|
||||
if (!valid) {
|
||||
// รวบรวม Error ทั้งหมดส่งกลับไป
|
||||
const errors = validate.errors
|
||||
?.map((e: any) => `${e.instancePath} ${e.message}`)
|
||||
.join(', ');
|
||||
// โยน Error กลับไปเพื่อให้ Controller/Service ปลายทางจัดการ
|
||||
throw new BadRequestException(`JSON Validation Failed: ${errors}`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ฟังก์ชันสำหรับสร้าง/อัปเดต Schema (สำหรับ Admin)
|
||||
async createOrUpdate(schemaCode: string, definition: any) {
|
||||
// ตรวจสอบก่อนว่า Definition เป็น JSON Schema ที่ถูกต้องไหม
|
||||
/**
|
||||
* สร้างหรืออัปเดต Schema
|
||||
*/
|
||||
async createOrUpdate(schemaCode: string, definition: Record<string, any>) {
|
||||
// 1. ตรวจสอบว่า Definition เป็น JSON Schema ที่ถูกต้องไหม
|
||||
try {
|
||||
this.ajv.compile(definition);
|
||||
} catch (error: any) {
|
||||
@@ -80,6 +82,7 @@ export class JsonSchemaService implements OnModuleInit {
|
||||
);
|
||||
}
|
||||
|
||||
// 2. บันทึกลง DB
|
||||
let schema = await this.schemaRepo.findOne({ where: { schemaCode } });
|
||||
|
||||
if (schema) {
|
||||
@@ -93,9 +96,12 @@ export class JsonSchemaService implements OnModuleInit {
|
||||
});
|
||||
}
|
||||
|
||||
// Clear Cache เก่า
|
||||
this.validators.delete(schemaCode);
|
||||
const savedSchema = await this.schemaRepo.save(schema);
|
||||
|
||||
return this.schemaRepo.save(schema);
|
||||
// 3. Clear Cache เพื่อให้ครั้งหน้าโหลดตัวใหม่
|
||||
this.validators.delete(schemaCode);
|
||||
this.logger.log(`Schema '${schemaCode}' updated (v${savedSchema.version})`);
|
||||
|
||||
return savedSchema;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user