form done

This commit is contained in:
OkaykOrhmn 2025-07-14 10:35:51 +03:30
parent 5d81857598
commit f17cd3c0f7
6 changed files with 238 additions and 0 deletions

View File

@ -0,0 +1,31 @@
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 { CreateQuestionDto } from '../../question/dto/create-question.dto';
import { CreateFormPageDto } from '../../formPage/dto/create-formPage.dto';
import { CreateParticipantDto } from '../../participant/dto/create-participant.dto';
export class CreateFormDto extends BaseDto {
@IsString()
title: string;
@IsString()
description: string;
@IsArray()
@ValidateNested({ each: true })
@Type(() => CreateAttachmentDto)
@IsOptional()
attachments?: CreateAttachmentDto[];
@IsArray()
@ValidateNested({ each: true })
@Type(() => CreateFormPageDto)
pages: CreateFormPageDto[];
@IsArray()
@ValidateNested({ each: true })
@Type(() => CreateParticipantDto)
participants: CreateParticipantDto[];
}

View File

@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateFormDto } from './create-form.dto';
export class UpdateFormDto extends PartialType(CreateFormDto) {}

View File

@ -0,0 +1,58 @@
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 { Participant, ParticipantSchema } from '../../participant/entity/participant.entity';
import { FormPage, FormPageSchema } from '../../formPage/entity/formPage.entity';
@Schema({ _id: false, id: false }) // Disable _id and virtual id
export class Form extends BaseEntity {
@Prop({
type: String,
required: true,
})
title: string;
@Prop({
type: String,
required: true,
})
description: string;
@Prop({
type: [AttachmentSchema],
default: [],
})
attachments: Attachment[];
@Prop({
type: [FormPageSchema],
default: [],
})
pages: FormPage[];
@Prop({
type: [ParticipantSchema],
default: [],
})
participants: Participant[];
}
export type FormDocument = Form & Document;
export const FormSchema = SchemaFactory.createForClass(Form);
FormSchema.plugin(mongoosePaginate);
// Transform the output to remove the internal '_id'
FormSchema.set('toJSON', {
transform: (doc: FormDocument, ret: Form & { _id?: any }) => {
delete ret._id;
return ret;
},
});

View File

@ -0,0 +1,47 @@
import { Controller, Get, Post, Patch, Delete, Param, Body, UsePipes, ValidationPipe, Query, ParseUUIDPipe, HttpCode, HttpStatus,} from '@nestjs/common';
import { FormService } from './form.service';
import { CreateFormDto } from './dto/create-form.dto';
import { UpdateFormDto } from './dto/update-form.dto';
import { Form } from './entity/form.entity';
@Controller('forms')
export class FormController {
constructor(private readonly formService: FormService) {}
@Post()
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
async create(@Body() body: CreateFormDto): Promise<Form> {
return this.formService.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.formService.findAll(parseInt(page, 10), parseInt(limit, 10));
}
@Get(':id')
async findOne(
@Param('id', new ParseUUIDPipe()) id: string,
): Promise<Form | null> {
return this.formService.findById(id);
}
@Patch(':id')
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
async update(
@Param('id', new ParseUUIDPipe()) id: string,
@Body() body: UpdateFormDto,
): Promise<Form | null> {
return this.formService.update(id, body);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise<void> {
return this.formService.remove(id);
}
}

16
src/form/form.module.ts Normal file
View File

@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { FormService } from './form.service';
import { FormController } from './form.controller';
import { Form, FormSchema } from './entity/form.entity';
@Module({
imports: [
MongooseModule.forFeature([
{ name: Form.name, schema: FormSchema },
]),
],
controllers: [FormController],
providers: [FormService],
})
export class FormModule {}

82
src/form/form.service.ts Normal file
View File

@ -0,0 +1,82 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Form, FormDocument } from './entity/form.entity';
import { CreateFormDto } from './dto/create-form.dto';
import { UpdateFormDto } from './dto/update-form.dto';
import { PaginateModel } from '../participant/participant.service';
@Injectable()
export class FormService {
constructor(
@InjectModel(Form.name)
private readonly formModel: PaginateModel<FormDocument>,
) {}
async create(data: CreateFormDto): Promise<Form> {
const form = new this.formModel({
...data,
id: data.id || undefined, // Let BaseEntity generate UUID if not provided
metadata: data.metadata || { entries: [] },
});
return form.save();
}
async findAll(
page = 1,
limit = 10,
): Promise<{
docs: Form[];
totalDocs: number;
limit: number;
page: number;
totalPages: number;
hasNextPage: boolean;
hasPrevPage: boolean;
nextPage: number | null;
prevPage: number | null;
}> {
// Selects all fields from the Form entity for the response
return this.formModel.paginate(
{},
{ page, limit, lean: true },
);
}
async findById(id: string): Promise<Form | null> {
const form = await this.formModel
.findOne({ id })
.lean()
.exec();
if (!form) {
throw new NotFoundException(`Form with ID "${id}" not found`);
}
return form;
}
async update(
id: string,
data: UpdateFormDto,
): Promise<Form | null> {
const updatedForm = await this.formModel
.findOneAndUpdate(
{ id },
{ $set: { ...data, updatedAt: new Date() } },
{ new: true },
)
.lean()
.exec();
if (!updatedForm) {
throw new NotFoundException(`Form with ID "${id}" not found`);
}
return updatedForm;
}
async remove(id: string): Promise<void> {
const result = await this.formModel.deleteOne({ id }).exec();
if (result.deletedCount === 0) {
throw new NotFoundException(`Form with ID "${id}" not found`);
}
}
}