This commit is contained in:
2026-01-28 16:33:30 +03:30
parent e7b5e96b5d
commit 4dc42aa676
10 changed files with 93 additions and 65 deletions
@@ -10,7 +10,7 @@ import { UpdateFieldOptionDto } from '../dto/update-field-option.dto';
@Controller('admin') @Controller('admin')
@ApiBearerAuth() @ApiBearerAuth()
export class FormBuilderController { export class FormBuilderController {
constructor( constructor(
private readonly fieldService: FieldService, private readonly fieldService: FieldService,
private readonly fieldOptionService: FieldOptionService, private readonly fieldOptionService: FieldOptionService,
@@ -19,36 +19,36 @@ import { UpdateFieldOptionDto } from '../dto/update-field-option.dto';
/*================================ Field ========================== */ /*================================ Field ========================== */
@Post('section/:id/field') @Post('entity/:id/field')
@ApiOperation({ summary: 'Create field for section' }) @ApiOperation({ summary: 'Create field for entity' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
createField(@Body() dto: CreateFieldDto, @Param('id') sectionId: string) { createField(@Body() dto: CreateFieldDto, @Param('id') entityId: string) {
return this.fieldService.create(sectionId,dto); return this.fieldService.create(+entityId, dto);
} }
@Get('section/:id/field') @Get('entity/:id/field')
@ApiOperation({ summary: 'find all secion fields' }) @ApiOperation({ summary: 'find all secion fields' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
findAllSectionFields(@Param('id') sectionId: string) { findAllSectionFields(@Param('id') entityId: string) {
return this.fieldService.findAll(+sectionId); return this.fieldService.findAll(+entityId);
} }
@Get('section/field/:id') @Get('entity/field/:id')
@ApiOperation({ summary: 'Find one field' }) @ApiOperation({ summary: 'Find one field' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
findOneFiled(@Param('id') id: string) { findOneFiled(@Param('id') id: string) {
return this.fieldService.findById(+id); return this.fieldService.findById(+id);
} }
@Patch('section/field/:id') @Patch('entity/field/:id')
@ApiOperation({ summary: 'Update field' }) @ApiOperation({ summary: 'Update field' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
updateField(@Param('id') id: string, @Body() dto: UpdateFieldDto) { updateField(@Param('id') id: string, @Body() dto: UpdateFieldDto) {
return this.fieldService.update(+id, dto); return this.fieldService.update(+id, dto);
} }
@Delete('section/field/:id') @Delete('entity/field/:id')
@ApiOperation({ summary: 'Renopve field' }) @ApiOperation({ summary: 'Remove field' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
removeField(@Param('id') id: string) { removeField(@Param('id') id: string) {
return this.fieldService.remove(+id); return this.fieldService.remove(+id);
@@ -56,35 +56,35 @@ import { UpdateFieldOptionDto } from '../dto/update-field-option.dto';
/*================================ Field Option ========================== */ /*================================ Field Option ========================== */
@Post('field/:id/option') @Post('entity/field/:id/option')
@ApiOperation({ summary: 'Create field Options ' }) @ApiOperation({ summary: 'Create field Options ' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
createFieldOption(@Body() dto: CreateFieldOptionDto, @Param('id') id: string) { createFieldOption(@Body() dto: CreateFieldOptionDto, @Param('id') id: string) {
return this.fieldOptionService.create(+id, dto); return this.fieldOptionService.create(+id, dto);
} }
@Get('field/:id/option') @Get('entity/field/:id/option')
@ApiOperation({ summary: 'find all field Option' }) @ApiOperation({ summary: 'find all field Option' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
findAllFiledOptions(@Param('id') fieldId: string) { findAllFiledOptions(@Param('id') fieldId: string) {
return this.fieldOptionService.findAll(+fieldId); return this.fieldOptionService.findAll(+fieldId);
} }
@Get('field/option/:id') @Get('entity/field/option/:id')
@ApiOperation({ summary: 'Find one field Option' }) @ApiOperation({ summary: 'Find one field Option' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
findOneFiledOption(@Param('id') id: string) { findOneFiledOption(@Param('id') id: string) {
return this.fieldOptionService.findById(+id); return this.fieldOptionService.findById(+id);
} }
@Patch('field/option/:id') @Patch('entity/field/option/:id')
@ApiOperation({ summary: 'Update field Option' }) @ApiOperation({ summary: 'Update field Option' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
updateFieldOption(@Param('id') id: string, @Body() dto: UpdateFieldOptionDto) { updateFieldOption(@Param('id') id: string, @Body() dto: UpdateFieldOptionDto) {
return this.fieldOptionService.update(+id, dto); return this.fieldOptionService.update(+id, dto);
} }
@Delete('field/option/:id') @Delete('entity/field/option/:id')
@ApiOperation({ summary: 'Renopve field Option' }) @ApiOperation({ summary: 'Renopve field Option' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
removeFieldOption(@Param('id') id: string) { removeFieldOption(@Param('id') id: string) {
@@ -1,7 +1,7 @@
import { IsString, IsOptional, IsBoolean, IsInt, Min, IsEnum, IsNotEmpty } from 'class-validator'; import { IsString, IsOptional, IsBoolean, IsInt, Min, IsEnum, IsNotEmpty } from 'class-validator';
import { ApiPropertyOptional, ApiProperty } from '@nestjs/swagger'; import { ApiPropertyOptional, ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { FieldType } from '../interface/print'; import { EntityType, FieldType } from '../interface/print';
export class CreateFieldDto { export class CreateFieldDto {
@IsString() @IsString()
@@ -23,6 +23,12 @@ export class CreateFieldDto {
@ApiProperty({ enum: FieldType, example: FieldType.select }) @ApiProperty({ enum: FieldType, example: FieldType.select })
type: FieldType; type: FieldType;
@IsNotEmpty()
@IsEnum(EntityType)
@ApiProperty({ enum: EntityType, example: EntityType.product })
entityType: EntityType
@IsOptional() @IsOptional()
@IsInt() @IsInt()
@Min(0) @Min(0)
@@ -1,9 +1,7 @@
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'; import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core';
import { FieldOption } from './field-option.entity'; import { FieldOption } from './field-option.entity';
import { FieldType } from '../interface/print'; import { EntityType, FieldType } from '../interface/print';
import { Section } from 'src/modules/print/entities/section.entity';
import { BaseEntity } from 'src/common/entities/base.entity'; import { BaseEntity } from 'src/common/entities/base.entity';
import { Product } from 'src/modules/product/entities/product.entity';
@Entity({ tableName: 'field' }) @Entity({ tableName: 'field' })
@@ -14,11 +12,13 @@ export class Field extends BaseEntity {
@OneToMany(() => FieldOption, (attrValue) => attrValue.field) @OneToMany(() => FieldOption, (attrValue) => attrValue.field)
options = new Collection<FieldOption>(this) options = new Collection<FieldOption>(this)
@ManyToOne(() => Section, { nullable: true }) // Discriminator column
section?: Section @Enum(() => EntityType) // Product , Print
entityType: EntityType;
@ManyToOne(() => Product, { nullable: true }) // Foreign key based on entityType
product?: Product @Property({ type: 'bigint' })
entityId: bigint;
@Property() @Property()
name: string; name: string;
@@ -6,4 +6,9 @@ export enum FieldType {
radio = 'radio', radio = 'radio',
checkbox = 'checkbox', checkbox = 'checkbox',
date = 'date', date = 'date',
}
export enum EntityType {
product = 'product',
print = 'print',
} }
@@ -2,35 +2,52 @@ import { BadRequestException, Injectable, NotFoundException } from '@nestjs/comm
import { EntityManager } from '@mikro-orm/postgresql'; import { EntityManager } from '@mikro-orm/postgresql';
import { RequiredEntityData } from '@mikro-orm/core'; import { RequiredEntityData } from '@mikro-orm/core';
import { FieldRepository } from '../repository/field.repository'; import { FieldRepository } from '../repository/field.repository';
import { SectionRepository } from 'src/modules/print/repository/section.repository'; import { PrintRepository } from 'src/modules/print/repository/print.repository';
import { Field } from '../entities/field.entity'; import { Field } from '../entities/field.entity';
import { CreateFieldDto } from '../dto/create-field.dto'; import { CreateFieldDto } from '../dto/create-field.dto';
import { UpdateFieldDto } from '../dto/update-field.dto'; import { UpdateFieldDto } from '../dto/update-field.dto';
import { ProductRepository } from 'src/modules/product/repositories/product.repository';
import { EntityType } from '../interface/print';
import { Product } from 'src/modules/product/entities/product.entity';
import { Print } from 'src/modules/print/entities/print.entity';
import { ProductService } from 'src/modules/product/providers/product.service';
import { PrintService } from 'src/modules/print/provider/Print.service';
@Injectable() @Injectable()
export class FieldService { export class FieldService {
constructor( constructor(
private readonly sectionRepository: SectionRepository, private readonly sectionRepository: PrintRepository,
private readonly fieldRepository: FieldRepository, private readonly fieldRepository: FieldRepository,
private readonly productService: ProductService,
private readonly printService: PrintService,
private readonly em: EntityManager, private readonly em: EntityManager,
) { } ) { }
async create(sectionId: string, dto: CreateFieldDto) { async create(entityId: number, dto: CreateFieldDto) {
const section = await this.sectionRepository.findOne({ id: sectionId }) const { entityType, isRequired, multiple, name, type, order } = dto
if (!section) { let entity: null | Product | Print = null
throw new BadRequestException("Section not found !")
if (entityType == EntityType.product) {
entity = await this.productService.findOneOrFail(entityId)
} else if (entityType == EntityType.print) {
entity = await this.printService.findOneOrFail(entityId)
}
if(!entity){
throw new BadRequestException("Entity not Found")
} }
const data: RequiredEntityData<Field> = { const data: RequiredEntityData<Field> = {
name: dto.name, name,
order: dto.order, order,
type: dto.type, type,
section, isRequired,
isRequired: dto.isRequired, multiple,
multiple: dto.multiple entityId:entity.id,
entityType
}; };
const field = this.fieldRepository.create(data) const field = this.fieldRepository.create(data)
@@ -57,9 +74,9 @@ export class FieldService {
} }
findAll(sectionId: number) { findAll(entityId: number) {
return this.fieldRepository.find({ return this.fieldRepository.find({
section: { id: sectionId } entityId
}, },
{ populate: ['options', 'options.value'] }); { populate: ['options', 'options.value'] });
} }
@@ -1,5 +1,5 @@
import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards } from '@nestjs/common'; import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards } from '@nestjs/common';
import { SectionService } from '../provider/section.service'; import { PrintService } from '../provider/Print.service';
import { CreateSectionDto } from '../dto/create-section.dto'; import { CreateSectionDto } from '../dto/create-section.dto';
import { ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { AdminAuthGuard } from '../../auth/guards/adminAuth.guard'; import { AdminAuthGuard } from '../../auth/guards/adminAuth.guard';
@@ -9,7 +9,7 @@ import { UpdateSectionDto } from '../dto/update-section.dto';
@ApiBearerAuth() @ApiBearerAuth()
export class PrintController { export class PrintController {
constructor( constructor(
private readonly sectionService: SectionService, private readonly sectionService: PrintService,
) { } ) { }
/*================================ Section ========================== */ /*================================ Section ========================== */
@@ -32,7 +32,7 @@ export class PrintController {
@ApiOperation({ summary: 'Find one section' }) @ApiOperation({ summary: 'Find one section' })
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
findOne(@Param('id') id: string) { findOne(@Param('id') id: string) {
return this.sectionService.findById(+id); return this.sectionService.findOneOrFail(+id);
} }
@Patch('section/:id') @Patch('section/:id')
@@ -3,12 +3,12 @@ import { Field } from 'src/modules/form-builder/entities/field.entity';
import { BaseEntity } from 'src/common/entities/base.entity'; import { BaseEntity } from 'src/common/entities/base.entity';
@Entity({ tableName: 'section' }) @Entity({ tableName: 'print' })
export class Section extends BaseEntity { export class Print extends BaseEntity {
@PrimaryKey({ type: 'bigint', autoincrement: true }) @PrimaryKey({ type: 'bigint', autoincrement: true })
id: bigint id: bigint
@OneToMany(() => Field, (attrValue) => attrValue.section, { cascade: [Cascade.PERSIST, Cascade.REMOVE] }) @OneToMany(() => Field, (attrValue) => attrValue.entityId, { cascade: [Cascade.PERSIST, Cascade.REMOVE] })
fields = new Collection<Field>(this) fields = new Collection<Field>(this)
@Property() @Property()
+8 -8
View File
@@ -1,21 +1,21 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { SectionService } from './provider/section.service'; import { PrintService } from './provider/Print.service';
import { PrintController } from './controller/print.controller'; import { PrintController } from './controller/print.controller';
import { MikroOrmModule } from '@mikro-orm/nestjs'; import { MikroOrmModule } from '@mikro-orm/nestjs';
import { Section } from './entities/section.entity'; import { Print } from './entities/print.entity';
import { SectionRepository } from './repository/section.repository'; import { PrintRepository } from './repository/print.repository';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { RolesModule } from '../roles/roles.module'; import { RolesModule } from '../roles/roles.module';
@Module({ @Module({
controllers: [PrintController], controllers: [PrintController],
providers: [SectionService, providers: [PrintService,
SectionRepository], PrintRepository],
exports: [SectionService, exports: [PrintService,
SectionRepository], PrintRepository],
imports: [MikroOrmModule.forFeature([Section]), imports: [MikroOrmModule.forFeature([Print]),
RolesModule, JwtModule.register({})] RolesModule, JwtModule.register({})]
}) })
export class PrintModule { } export class PrintModule { }
@@ -1,23 +1,23 @@
import { Injectable, NotFoundException } from '@nestjs/common'; import { Injectable, NotFoundException } from '@nestjs/common';
import { EntityManager } from '@mikro-orm/postgresql'; import { EntityManager } from '@mikro-orm/postgresql';
import { RequiredEntityData } from '@mikro-orm/core'; import { RequiredEntityData } from '@mikro-orm/core';
import { SectionRepository } from '../repository/section.repository'; import { PrintRepository } from '../repository/print.repository';
import { CreateSectionDto } from '../dto/create-section.dto'; import { CreateSectionDto } from '../dto/create-section.dto';
import { Section } from '../entities/section.entity'; import { Print } from '../entities/print.entity';
import { UpdateSectionDto } from '../dto/update-section.dto'; import { UpdateSectionDto } from '../dto/update-section.dto';
@Injectable() @Injectable()
export class SectionService { export class PrintService {
constructor( constructor(
private readonly sectionRepository: SectionRepository, private readonly sectionRepository: PrintRepository,
private readonly em: EntityManager, private readonly em: EntityManager,
) { } ) { }
async create(dto: CreateSectionDto) { async create(dto: CreateSectionDto) {
const data: RequiredEntityData<Section> = { const data: RequiredEntityData<Print> = {
title: dto.title, title: dto.title,
order: dto.order, order: dto.order,
}; };
@@ -35,7 +35,7 @@ export class SectionService {
const section = await this.sectionRepository.findOne({ id: sectionId }) const section = await this.sectionRepository.findOne({ id: sectionId })
if (!section) { if (!section) {
throw new NotFoundException('Section not found'); throw new NotFoundException('Print not found');
} }
this.sectionRepository.assign(section, dto) this.sectionRepository.assign(section, dto)
@@ -50,16 +50,16 @@ export class SectionService {
return this.sectionRepository.findAll({ populate: ['fields', 'fields.options', 'fields.options.value'] }); return this.sectionRepository.findAll({ populate: ['fields', 'fields.options', 'fields.options.value'] });
} }
async findById(attributeId: number): Promise<Section> { async findOneOrFail(attributeId: number): Promise<Print> {
const section = await this.sectionRepository.findOne({ id: attributeId }, const section = await this.sectionRepository.findOne({ id: attributeId },
{ populate: ['fields', 'fields.options', 'fields.options.value'] }); { populate: ['fields', 'fields.options', 'fields.options.value'] });
if (!section) throw new NotFoundException('Section not found'); if (!section) throw new NotFoundException('Print not found');
return section; return section;
} }
async remove(id: number): Promise<void> { async remove(id: number): Promise<void> {
const section = await this.findById(id); const section = await this.findOneOrFail(id);
section.deletedAt = new Date(); section.deletedAt = new Date();
return await this.em.persistAndFlush(section); return await this.em.persistAndFlush(section);
@@ -1,11 +1,11 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql'; import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
import { Section } from '../entities/section.entity'; import { Print } from '../entities/print.entity';
@Injectable() @Injectable()
export class SectionRepository extends EntityRepository<Section> { export class PrintRepository extends EntityRepository<Print> {
constructor(readonly em: EntityManager) { constructor(readonly em: EntityManager) {
super(em, Section); super(em, Print);
} }
} }