formSection done
This commit is contained in:
parent
89f0fdbb60
commit
844e8f40c1
|
|
@ -0,0 +1,42 @@
|
|||
import { IsNumber, IsString, IsOptional, IsUUID, ValidateNested, IsArray, IsDateString } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { BaseDto } from '../../_core/dto/base.dto';
|
||||
|
||||
// DTO for Options
|
||||
class CreateOptionsDto {
|
||||
@IsString()
|
||||
value: string;
|
||||
|
||||
@IsNumber()
|
||||
count: number;
|
||||
}
|
||||
|
||||
// DTO for Opinion
|
||||
class CreateOpinionDto {
|
||||
@ValidateNested()
|
||||
@Type(() => CreateOptionsDto)
|
||||
options: CreateOptionsDto;
|
||||
|
||||
@IsUUID()
|
||||
questionId: string;
|
||||
}
|
||||
|
||||
// Main DTO for creating a FormResult
|
||||
export class CreateFormResultDto extends BaseDto {
|
||||
@IsNumber()
|
||||
numParticipants: number;
|
||||
|
||||
@IsNumber()
|
||||
numQuestions: number;
|
||||
|
||||
@IsNumber()
|
||||
numAnswers: number;
|
||||
|
||||
@IsNumber()
|
||||
numComplete: number;
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateOpinionDto)
|
||||
opinions: CreateOpinionDto[];
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateFormResultDto } from './create-formResult.dto';
|
||||
|
||||
export class UpdateFormResultDto extends PartialType(CreateFormResultDto) {}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
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 { UUID } from 'mongodb';
|
||||
|
||||
// Sub-schema for Options
|
||||
@Schema({ _id: false, id: false })
|
||||
class Options {
|
||||
@Prop({
|
||||
type: String,
|
||||
required: true,
|
||||
})
|
||||
value: string;
|
||||
|
||||
@Prop({
|
||||
type: Number,
|
||||
required: true,
|
||||
min: 0,
|
||||
default: 0
|
||||
})
|
||||
count: number;
|
||||
}
|
||||
|
||||
export const OptionsSchema = SchemaFactory.createForClass(Options);
|
||||
|
||||
// Sub-schema for Opinion
|
||||
@Schema({ _id: false, id: false })
|
||||
class Opinion {
|
||||
@Prop({
|
||||
type: OptionsSchema,
|
||||
required: true,
|
||||
})
|
||||
options: Options;
|
||||
|
||||
@Prop({
|
||||
type: UUID,
|
||||
required: true,
|
||||
})
|
||||
questionId: string;
|
||||
}
|
||||
export const OpinionSchema = SchemaFactory.createForClass(Opinion);
|
||||
|
||||
|
||||
@Schema({ _id: false, id: false }) // Disable _id and virtual id
|
||||
export class FormResult extends BaseEntity {
|
||||
@Prop({
|
||||
type: Number,
|
||||
required: true,
|
||||
min: 0,
|
||||
default: 0,
|
||||
})
|
||||
numParticipants: string;
|
||||
|
||||
@Prop({
|
||||
type: Number,
|
||||
required: true,
|
||||
min: 0,
|
||||
default: 0,
|
||||
})
|
||||
numQuestions: string;
|
||||
|
||||
@Prop({
|
||||
type: Number,
|
||||
required: true,
|
||||
min: 0,
|
||||
default: 0,
|
||||
})
|
||||
numAnswers: string;
|
||||
|
||||
@Prop({
|
||||
type: Number,
|
||||
required: true,
|
||||
min: 0,
|
||||
default: 0,
|
||||
})
|
||||
numComplete: string; // number of people who completed this form
|
||||
|
||||
@Prop({
|
||||
type: [OpinionSchema],
|
||||
default: [],
|
||||
})
|
||||
opinions: Opinion[];
|
||||
}
|
||||
|
||||
export type FormResultDocument = FormResult & Document;
|
||||
export const FormResultSchema = SchemaFactory.createForClass(FormResult);
|
||||
FormResultSchema.plugin(mongoosePaginate);
|
||||
|
||||
// Transform the output to remove the internal '_id'
|
||||
FormResultSchema.set('toJSON', {
|
||||
transform: (doc: FormResultDocument, ret: FormResult & { _id?: any }) => {
|
||||
delete ret._id;
|
||||
return ret;
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import { Controller, Get, Post, Patch, Delete, Param, Body, UsePipes, ValidationPipe, Query, ParseUUIDPipe, HttpCode, HttpStatus,} from '@nestjs/common';
|
||||
import { FormResultService } from './formResult.service';
|
||||
import { CreateFormResultDto } from './dto/create-formResult.dto';
|
||||
import { UpdateFormResultDto } from './dto/update-formResult.dto';
|
||||
import { FormResult } from './entity/formResult.entity';
|
||||
|
||||
@Controller('formResults')
|
||||
export class FormResultController {
|
||||
constructor(private readonly formResultService: FormResultService) {}
|
||||
|
||||
@Post()
|
||||
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
|
||||
async create(@Body() body: CreateFormResultDto): Promise<FormResult> {
|
||||
return this.formResultService.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.formResultService.findAll(parseInt(page, 10), parseInt(limit, 10));
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
async findOne(
|
||||
@Param('id', new ParseUUIDPipe()) id: string,
|
||||
): Promise<FormResult | null> {
|
||||
return this.formResultService.findById(id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
|
||||
async update(
|
||||
@Param('id', new ParseUUIDPipe()) id: string,
|
||||
@Body() body: UpdateFormResultDto,
|
||||
): Promise<FormResult | null> {
|
||||
return this.formResultService.update(id, body);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise<void> {
|
||||
return this.formResultService.remove(id);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { FormResultService } from './formResult.service';
|
||||
import { FormResultController } from './formResult.controller';
|
||||
import { FormResult, FormResultSchema } from './entity/formResult.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
MongooseModule.forFeature([
|
||||
{ name: FormResult.name, schema: FormResultSchema },
|
||||
]),
|
||||
],
|
||||
controllers: [FormResultController],
|
||||
providers: [FormResultService],
|
||||
})
|
||||
export class FormResultModule {}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
import { FormResult, FormResultDocument } from './entity/formResult.entity';
|
||||
import { CreateFormResultDto } from './dto/create-formResult.dto';
|
||||
import { UpdateFormResultDto } from './dto/update-formResult.dto';
|
||||
import { PaginateModel } from '../participant/participant.service';
|
||||
|
||||
@Injectable()
|
||||
export class FormResultService {
|
||||
constructor(
|
||||
@InjectModel(FormResult.name)
|
||||
private readonly formResultModel: PaginateModel<FormResultDocument>,
|
||||
) {}
|
||||
|
||||
async create(data: CreateFormResultDto): Promise<FormResult> {
|
||||
const formResult = new this.formResultModel({
|
||||
...data,
|
||||
id: data.id || undefined, // Let BaseEntity generate UUID if not provided
|
||||
metadata: data.metadata || { entries: [] },
|
||||
});
|
||||
return formResult.save();
|
||||
}
|
||||
|
||||
async findAll(
|
||||
page = 1,
|
||||
limit = 10,
|
||||
): Promise<{
|
||||
docs: FormResult[];
|
||||
totalDocs: number;
|
||||
limit: number;
|
||||
page: number;
|
||||
totalPages: number;
|
||||
hasNextPage: boolean;
|
||||
hasPrevPage: boolean;
|
||||
nextPage: number | null;
|
||||
prevPage: number | null;
|
||||
}> {
|
||||
// Selects all fields from the FormResult entity for the response
|
||||
return this.formResultModel.paginate(
|
||||
{},
|
||||
{ page, limit, lean: true },
|
||||
);
|
||||
}
|
||||
|
||||
async findById(id: string): Promise<FormResult | null> {
|
||||
const formResult = await this.formResultModel
|
||||
.findOne({ id })
|
||||
.lean()
|
||||
.exec();
|
||||
if (!formResult) {
|
||||
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
||||
}
|
||||
return formResult;
|
||||
}
|
||||
|
||||
async update(
|
||||
id: string,
|
||||
data: UpdateFormResultDto,
|
||||
): Promise<FormResult | null> {
|
||||
const updatedFormResult = await this.formResultModel
|
||||
.findOneAndUpdate(
|
||||
{ id },
|
||||
{ $set: { ...data, updatedAt: new Date() } },
|
||||
{ new: true },
|
||||
)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (!updatedFormResult) {
|
||||
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
||||
}
|
||||
return updatedFormResult;
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
const result = await this.formResultModel.deleteOne({ id }).exec();
|
||||
if (result.deletedCount === 0) {
|
||||
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
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';
|
||||
|
||||
// DTO for DisplayCondition
|
||||
export class CreateDisplayConditionDto {
|
||||
@IsUUID()
|
||||
answer: string;
|
||||
|
||||
@IsUUID()
|
||||
question: string;
|
||||
|
||||
@IsEnum(['equal', 'contains', 'not_equal', 'not_contains'])
|
||||
relation: 'equal' | 'contains' | 'not_equal' | 'not_contains';
|
||||
}
|
||||
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
|
||||
export class CreateFormSectionDto extends BaseDto {
|
||||
@IsString()
|
||||
title: string;
|
||||
|
||||
@IsString()
|
||||
description: string;
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateAttachmentDto)
|
||||
@IsOptional()
|
||||
attachments?: CreateAttachmentDto[];
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateDisplayConditionDto)
|
||||
@IsOptional()
|
||||
displayCondition?: CreateDisplayConditionDto[];
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateQuestionDto)
|
||||
@IsOptional()
|
||||
questions?: CreateQuestionDto[];
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateFormSectionDto } from './create-formSection.dto';
|
||||
|
||||
export class UpdateFormSectionDto extends PartialType(CreateFormSectionDto) {}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
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';
|
||||
|
||||
// Sub-schema for DisplayContition
|
||||
@Schema({ _id: false, id: false })
|
||||
export class DisplayCondition {
|
||||
@Prop({
|
||||
type: [AnswerSchema],
|
||||
required: true,
|
||||
})
|
||||
answer: Answer;
|
||||
|
||||
@Prop({
|
||||
type: [QuestionSchema],
|
||||
required: true,
|
||||
})
|
||||
question: Question;
|
||||
|
||||
@Prop({
|
||||
type: String,
|
||||
enum: ['equal','contains','not_equal','not_contains'],
|
||||
required: true,
|
||||
})
|
||||
relation: 'equal'|'contains'|'not_equal'|'not_contains';
|
||||
}
|
||||
|
||||
export const DisplayConditionSchema = SchemaFactory.createForClass(DisplayCondition);
|
||||
|
||||
|
||||
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
|
||||
|
||||
@Schema({ _id: false, id: false }) // Disable _id and virtual id
|
||||
export class FormSection extends BaseEntity {
|
||||
@Prop({
|
||||
type: String,
|
||||
required: true,
|
||||
})
|
||||
title: string;
|
||||
|
||||
@Prop({
|
||||
type: String,
|
||||
required: true,
|
||||
})
|
||||
description: string;
|
||||
|
||||
@Prop({
|
||||
type: [AttachmentSchema],
|
||||
default: [],
|
||||
})
|
||||
attachments: Attachment[];
|
||||
|
||||
@Prop({
|
||||
type: [DisplayContidionSchema],
|
||||
default: [],
|
||||
})
|
||||
displayCondition: DisplayContidion[];
|
||||
|
||||
@Prop({
|
||||
type: [QuestionSchema],
|
||||
default: [],
|
||||
})
|
||||
questions: Question[];
|
||||
|
||||
}
|
||||
|
||||
export type FormSectionDocument = FormSection & Document;
|
||||
export const FormSectionSchema = SchemaFactory.createForClass(FormSection);
|
||||
FormSectionSchema.plugin(mongoosePaginate);
|
||||
|
||||
// Transform the output to remove the internal '_id'
|
||||
FormSectionSchema.set('toJSON', {
|
||||
transform: (doc: FormSectionDocument, ret: FormSection & { _id?: any }) => {
|
||||
delete ret._id;
|
||||
return ret;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import { Controller, Get, Post, Patch, Delete, Param, Body, UsePipes, ValidationPipe, Query, ParseUUIDPipe, HttpCode, HttpStatus,} from '@nestjs/common';
|
||||
import { FormSectionService } from './formSection.service';
|
||||
import { CreateFormSectionDto } from './dto/create-formSection.dto';
|
||||
import { UpdateFormSectionDto } from './dto/update-formSection.dto';
|
||||
import { FormSection } from './entity/formSection.entity';
|
||||
|
||||
@Controller('formSections')
|
||||
export class FormSectionController {
|
||||
constructor(private readonly formSectionService: FormSectionService) {}
|
||||
|
||||
@Post()
|
||||
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
|
||||
async create(@Body() body: CreateFormSectionDto): Promise<FormSection> {
|
||||
return this.formSectionService.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.formSectionService.findAll(parseInt(page, 10), parseInt(limit, 10));
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
async findOne(
|
||||
@Param('id', new ParseUUIDPipe()) id: string,
|
||||
): Promise<FormSection | null> {
|
||||
return this.formSectionService.findById(id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
|
||||
async update(
|
||||
@Param('id', new ParseUUIDPipe()) id: string,
|
||||
@Body() body: UpdateFormSectionDto,
|
||||
): Promise<FormSection | null> {
|
||||
return this.formSectionService.update(id, body);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise<void> {
|
||||
return this.formSectionService.remove(id);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { FormSectionService } from './formSection.service';
|
||||
import { FormSectionController } from './formSection.controller';
|
||||
import { FormSection, FormSectionSchema } from './entity/formSection.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
MongooseModule.forFeature([
|
||||
{ name: FormSection.name, schema: FormSectionSchema },
|
||||
]),
|
||||
],
|
||||
controllers: [FormSectionController],
|
||||
providers: [FormSectionService],
|
||||
})
|
||||
export class FormSectionModule {}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
import { FormSection, FormSectionDocument } from './entity/formSection.entity';
|
||||
import { CreateFormSectionDto } from './dto/create-formSection.dto';
|
||||
import { UpdateFormSectionDto } from './dto/update-formSection.dto';
|
||||
import { PaginateModel } from '../participant/participant.service';
|
||||
|
||||
@Injectable()
|
||||
export class FormSectionService {
|
||||
constructor(
|
||||
@InjectModel(FormSection.name)
|
||||
private readonly formSectionModel: PaginateModel<FormSectionDocument>,
|
||||
) {}
|
||||
|
||||
async create(data: CreateFormSectionDto): Promise<FormSection> {
|
||||
const formSection = new this.formSectionModel({
|
||||
...data,
|
||||
id: data.id || undefined, // Let BaseEntity generate UUID if not provided
|
||||
metadata: data.metadata || { entries: [] },
|
||||
});
|
||||
return formSection.save();
|
||||
}
|
||||
|
||||
async findAll(
|
||||
page = 1,
|
||||
limit = 10,
|
||||
): Promise<{
|
||||
docs: FormSection[];
|
||||
totalDocs: number;
|
||||
limit: number;
|
||||
page: number;
|
||||
totalPages: number;
|
||||
hasNextPage: boolean;
|
||||
hasPrevPage: boolean;
|
||||
nextPage: number | null;
|
||||
prevPage: number | null;
|
||||
}> {
|
||||
// Selects all fields from the FormSection entity for the response
|
||||
return this.formSectionModel.paginate(
|
||||
{},
|
||||
{ page, limit, lean: true },
|
||||
);
|
||||
}
|
||||
|
||||
async findById(id: string): Promise<FormSection | null> {
|
||||
const formSection = await this.formSectionModel
|
||||
.findOne({ id })
|
||||
.lean()
|
||||
.exec();
|
||||
if (!formSection) {
|
||||
throw new NotFoundException(`FormSection with ID "${id}" not found`);
|
||||
}
|
||||
return formSection;
|
||||
}
|
||||
|
||||
async update(
|
||||
id: string,
|
||||
data: UpdateFormSectionDto,
|
||||
): Promise<FormSection | null> {
|
||||
const updatedFormSection = await this.formSectionModel
|
||||
.findOneAndUpdate(
|
||||
{ id },
|
||||
{ $set: { ...data, updatedAt: new Date() } },
|
||||
{ new: true },
|
||||
)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (!updatedFormSection) {
|
||||
throw new NotFoundException(`FormSection with ID "${id}" not found`);
|
||||
}
|
||||
return updatedFormSection;
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
const result = await this.formSectionModel.deleteOne({ id }).exec();
|
||||
if (result.deletedCount === 0) {
|
||||
throw new NotFoundException(`FormSection with ID "${id}" not found`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue