diff --git a/src/formPage/dto/create-formPage.dto.ts b/src/formPage/dto/create-formPage.dto.ts new file mode 100644 index 0000000..84351ab --- /dev/null +++ b/src/formPage/dto/create-formPage.dto.ts @@ -0,0 +1,17 @@ +import { IsString, ValidateNested, IsArray } from 'class-validator'; +import { Type } from 'class-transformer'; +import { BaseDto } from '../../_core/dto/base.dto'; +import { CreateFormSectionDto } from '../../formSection/dto/create-formSection.dto'; + +export class CreateFormPageDto extends BaseDto { + @IsString() + title: string; + + @IsString() + description: string; + + @IsArray() + @ValidateNested({ each: true }) + @Type(() => CreateFormSectionDto) + formSections: CreateFormSectionDto[]; +} \ No newline at end of file diff --git a/src/formPage/dto/update-formPage.dto.ts b/src/formPage/dto/update-formPage.dto.ts new file mode 100644 index 0000000..a990976 --- /dev/null +++ b/src/formPage/dto/update-formPage.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateFormPageDto } from './create-formPage.dto'; + +export class UpdateFormPageDto extends PartialType(CreateFormPageDto) {} diff --git a/src/formPage/entity/formPage.entity.ts b/src/formPage/entity/formPage.entity.ts new file mode 100644 index 0000000..d2c78db --- /dev/null +++ b/src/formPage/entity/formPage.entity.ts @@ -0,0 +1,45 @@ +import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; +import { Document } from 'mongoose'; +import { BaseEntity } from 'src/_core/entity/_base.entity'; +import * as mongoosePaginate from 'mongoose-paginate-v2'; +import { Attachment, AttachmentSchema } from '../../attachment/entity/attachment.entity'; +import { Option, OptionSchema } from '../../option/entity/option.entity'; +import { Answer, AnswerSchema } from '../../answer/entity/answer.entity'; +import { Question, QuestionSchema } from '../../question/entity/question.entity'; +import { FormSection, FormSectionSchema } from '../../formSection/entity/formSection.entity'; + +@Schema({ _id: false, id: false }) // Disable _id and virtual id +export class FormPage extends BaseEntity { + @Prop({ + type: String, + required: true, + }) + title: string; + + @Prop({ + type: String, + required: true, + }) + description: string; + + @Prop({ + type: [FormSectionSchema], + default: [], + }) + attachments: FormSection[]; +} + +export type FormPageDocument = FormPage & Document; +export const FormPageSchema = SchemaFactory.createForClass(FormPage); +FormPageSchema.plugin(mongoosePaginate); + +// Transform the output to remove the internal '_id' +FormPageSchema.set('toJSON', { + transform: (doc: FormPageDocument, ret: FormPage & { _id?: any }) => { + delete ret._id; + return ret; + }, +}); + + + diff --git a/src/formPage/formPage.controller.ts b/src/formPage/formPage.controller.ts new file mode 100644 index 0000000..3e29fe4 --- /dev/null +++ b/src/formPage/formPage.controller.ts @@ -0,0 +1,47 @@ +import { Controller, Get, Post, Patch, Delete, Param, Body, UsePipes, ValidationPipe, Query, ParseUUIDPipe, HttpCode, HttpStatus,} from '@nestjs/common'; +import { FormPageService } from './formPage.service'; +import { CreateFormPageDto } from './dto/create-formPage.dto'; +import { UpdateFormPageDto } from './dto/update-formPage.dto'; +import { FormPage } from './entity/formPage.entity'; + +@Controller('formPages') +export class FormPageController { + constructor(private readonly formPageService: FormPageService) {} + + @Post() + @UsePipes(new ValidationPipe({ transform: true, whitelist: true })) + async create(@Body() body: CreateFormPageDto): Promise { + return this.formPageService.create(body); + } + + @Get('findAll') + async findAll( + @Query('page') page: string = '1', + @Query('limit') limit: string = '10', + ) { + // The service returns the full pagination object + return this.formPageService.findAll(parseInt(page, 10), parseInt(limit, 10)); + } + + @Get(':id') + async findOne( + @Param('id', new ParseUUIDPipe()) id: string, + ): Promise { + return this.formPageService.findById(id); + } + + @Patch(':id') + @UsePipes(new ValidationPipe({ transform: true, whitelist: true })) + async update( + @Param('id', new ParseUUIDPipe()) id: string, + @Body() body: UpdateFormPageDto, + ): Promise { + return this.formPageService.update(id, body); + } + + @Delete(':id') + @HttpCode(HttpStatus.NO_CONTENT) + async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise { + return this.formPageService.remove(id); + } +} diff --git a/src/formPage/formPage.module.ts b/src/formPage/formPage.module.ts new file mode 100644 index 0000000..9cec8b2 --- /dev/null +++ b/src/formPage/formPage.module.ts @@ -0,0 +1,16 @@ +import { Module } from '@nestjs/common'; +import { MongooseModule } from '@nestjs/mongoose'; +import { FormPageService } from './formPage.service'; +import { FormPageController } from './formPage.controller'; +import { FormPage, FormPageSchema } from './entity/formPage.entity'; + +@Module({ + imports: [ + MongooseModule.forFeature([ + { name: FormPage.name, schema: FormPageSchema }, + ]), + ], + controllers: [FormPageController], + providers: [FormPageService], +}) +export class FormPageModule {} diff --git a/src/formPage/formPage.service.ts b/src/formPage/formPage.service.ts new file mode 100644 index 0000000..b97c490 --- /dev/null +++ b/src/formPage/formPage.service.ts @@ -0,0 +1,82 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { InjectModel } from '@nestjs/mongoose'; +import { Model } from 'mongoose'; +import { FormPage, FormPageDocument } from './entity/formPage.entity'; +import { CreateFormPageDto } from './dto/create-formPage.dto'; +import { UpdateFormPageDto } from './dto/update-formPage.dto'; +import { PaginateModel } from '../participant/participant.service'; + +@Injectable() +export class FormPageService { + constructor( + @InjectModel(FormPage.name) + private readonly formPageModel: PaginateModel, + ) {} + + async create(data: CreateFormPageDto): Promise { + const formPage = new this.formPageModel({ + ...data, + id: data.id || undefined, // Let BaseEntity generate UUID if not provided + metadata: data.metadata || { entries: [] }, + }); + return formPage.save(); + } + + async findAll( + page = 1, + limit = 10, + ): Promise<{ + docs: FormPage[]; + totalDocs: number; + limit: number; + page: number; + totalPages: number; + hasNextPage: boolean; + hasPrevPage: boolean; + nextPage: number | null; + prevPage: number | null; + }> { + // Selects all fields from the FormPage entity for the response + return this.formPageModel.paginate( + {}, + { page, limit, lean: true }, + ); + } + + async findById(id: string): Promise { + const formPage = await this.formPageModel + .findOne({ id }) + .lean() + .exec(); + if (!formPage) { + throw new NotFoundException(`FormPage with ID "${id}" not found`); + } + return formPage; + } + + async update( + id: string, + data: UpdateFormPageDto, + ): Promise { + const updatedFormPage = await this.formPageModel + .findOneAndUpdate( + { id }, + { $set: { ...data, updatedAt: new Date() } }, + { new: true }, + ) + .lean() + .exec(); + + if (!updatedFormPage) { + throw new NotFoundException(`FormPage with ID "${id}" not found`); + } + return updatedFormPage; + } + + async remove(id: string): Promise { + const result = await this.formPageModel.deleteOne({ id }).exec(); + if (result.deletedCount === 0) { + throw new NotFoundException(`FormPage with ID "${id}" not found`); + } + } +} diff --git a/src/formSection/dto/create-formSection.dto.ts b/src/formSection/dto/create-formSection.dto.ts index 06c65db..861f0a8 100644 --- a/src/formSection/dto/create-formSection.dto.ts +++ b/src/formSection/dto/create-formSection.dto.ts @@ -1,7 +1,7 @@ import { IsString, IsOptional, IsUUID, ValidateNested, IsArray, IsEnum, IsDateString } from 'class-validator'; import { Type } from 'class-transformer'; import { BaseDto } from '../../_core/dto/base.dto'; -import { CreateAttachmentDto } from '../../attachment/dto/create-attachment.dto'; +import { CreateAttachmentDto } from '../../attachment/dto/create_attachment.dto'; import { CreateQuestionDto } from '../../question/dto/create-question.dto'; // DTO for DisplayCondition @@ -32,12 +32,10 @@ export class CreateFormSectionDto extends BaseDto { @IsArray() @ValidateNested({ each: true }) @Type(() => CreateDisplayConditionDto) - @IsOptional() - displayCondition?: CreateDisplayConditionDto[]; + displayCondition: CreateDisplayConditionDto[]; @IsArray() @ValidateNested({ each: true }) @Type(() => CreateQuestionDto) - @IsOptional() - questions?: CreateQuestionDto[]; + questions: CreateQuestionDto[]; } \ No newline at end of file