option folder is not tested and revised
This commit is contained in:
parent
11971398cb
commit
bdeef357ba
|
|
@ -4,6 +4,7 @@ import { MongooseModule } from '@nestjs/mongoose';
|
|||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { ParticipantModule } from './participant/participant.module';
|
||||
import { QuestionModule } from './question/question.module';
|
||||
// import { TestModule } from './test/test.module';
|
||||
|
||||
@Module({
|
||||
|
|
@ -13,6 +14,7 @@ import { ParticipantModule } from './participant/participant.module';
|
|||
}),
|
||||
MongooseModule.forRoot(process.env.MONGODB_URI || 'mongodb://localhost:27017/db'),
|
||||
ParticipantModule,
|
||||
QuestionModule
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ export class Attachment extends BaseEntity {
|
|||
|
||||
@Prop({
|
||||
type: String,
|
||||
enum: ['png', 'pdf', 'csv', 'jpg'],
|
||||
required: true,
|
||||
})
|
||||
fileType: string;
|
||||
fileType: 'png' | 'pdf' | 'csv' | 'jpg';
|
||||
|
||||
@Prop({
|
||||
type: String,
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import { IsString, IsOptional, ValidateNested } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
class MetadataEntryDto {
|
||||
@IsString()
|
||||
key: string;
|
||||
|
||||
@IsString()
|
||||
value: string;
|
||||
}
|
||||
|
||||
class MetadataDto {
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => MetadataEntryDto)
|
||||
entries: MetadataEntryDto[];
|
||||
}
|
||||
|
||||
export class CreateOptionDto {
|
||||
@IsString()
|
||||
text: string;
|
||||
|
||||
@ValidateNested()
|
||||
@Type(() => MetadataDto)
|
||||
@IsOptional()
|
||||
metadata?: MetadataDto;
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateOptionDto } from './create-option.dto';
|
||||
|
||||
export class UpdateOptionDto extends PartialType(CreateOptionDto) {}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import { Controller, Get, Post, Patch, Delete, Param, Body, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { ParseUUIDPipe } from '@nestjs/common';
|
||||
import { OptionService } from './option.service';
|
||||
import { CreateOptionDto } from './dto/create-option.dto';
|
||||
import { UpdateOptionDto } from './dto/update-option.dto';
|
||||
import { Option } from './entity/option.entity';
|
||||
import { Paginate, Paginated, PaginateQuery } from 'nestjs-paginate';
|
||||
|
||||
@Controller('options')
|
||||
export class OptionController {
|
||||
constructor(private readonly optionService: OptionService) {}
|
||||
|
||||
@Post()
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async create(@Body() body: CreateOptionDto): Promise<Option> {
|
||||
return this.optionService.create(body);
|
||||
}
|
||||
|
||||
@Get()
|
||||
async findAll(@Paginate() query: PaginateQuery): Promise<Paginated<Option>> {
|
||||
return this.optionService.findAll(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
async findOne(@Param('id', new ParseUUIDPipe()) id: string): Promise<Option | null> {
|
||||
return this.optionService.findById(id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async update(
|
||||
@Param('id', new ParseUUIDPipe()) id: string,
|
||||
@Body() body: UpdateOptionDto,
|
||||
): Promise<Option | null> {
|
||||
return this.optionService.update(id, body);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise<void> {
|
||||
return this.optionService.remove(id);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { OptionService } from './option.service';
|
||||
import { OptionController } from './option.controller';
|
||||
import { Option, OptionSchema } from './entity/option.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
MongooseModule.forFeature([{ name: Option.name, schema: OptionSchema }]),
|
||||
],
|
||||
controllers: [OptionController],
|
||||
providers: [OptionService],
|
||||
})
|
||||
export class OptionModule {}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
import { CreateOptionDto } from './dto/create-option.dto';
|
||||
import { UpdateOptionDto } from './dto/update-option.dto';
|
||||
import { Option, OptionDocument } from './entity/option.entity';
|
||||
import { PaginateQuery, Paginated, paginate } from 'nestjs-paginate';
|
||||
|
||||
|
||||
interface PaginateModel<T> extends Model<T> {
|
||||
paginate: (
|
||||
query?: any,
|
||||
options?: { page: number; limit: number; lean?: boolean; select?: string },
|
||||
) => Promise<{
|
||||
docs: T[];
|
||||
totalDocs: number;
|
||||
limit: number;
|
||||
page: number;
|
||||
totalPages: number;
|
||||
hasNextPage: boolean;
|
||||
hasPrevPage: boolean;
|
||||
nextPage: number | null;
|
||||
prevPage: number | null;
|
||||
}>;
|
||||
}
|
||||
@Injectable()
|
||||
export class OptionService {
|
||||
constructor(
|
||||
@InjectModel(Option.name)
|
||||
private readonly optionModel: PaginateModel<OptionDocument>,
|
||||
) {}
|
||||
|
||||
async create(data: CreateOptionDto): Promise<Option> {
|
||||
const option = new this.optionModel({ ...data, id: require('uuid').v4() });
|
||||
return option.save();
|
||||
}
|
||||
|
||||
async findAll(page = 1, limit = 10): Promise<{
|
||||
docs: Option[];
|
||||
totalDocs: number;
|
||||
limit: number;
|
||||
page: number;
|
||||
totalPages: number;
|
||||
hasNextPage: boolean;
|
||||
hasPrevPage: boolean;
|
||||
nextPage: number | null;
|
||||
prevPage: number | null;
|
||||
}> {
|
||||
return this.optionModel.paginate(
|
||||
{},
|
||||
{ page, limit, lean: true, select: 'id metadata status text createdAt updatedAt' },
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
async findById(id: string): Promise<Option | null> {
|
||||
return this.optionModel.findOne({ id }).lean().exec();
|
||||
}
|
||||
|
||||
async update(id: string, data: UpdateOptionDto): Promise<Option | null> {
|
||||
return this.optionModel
|
||||
.findOneAndUpdate({ id }, { ...data, updatedAt: new Date() }, { new: true })
|
||||
.lean()
|
||||
.exec();
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.optionModel.deleteOne({ id }).exec();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
|||
import { Document } from 'mongoose';
|
||||
import { BaseEntity } from 'src/_core/_base.entity';
|
||||
import * as mongoosePaginate from 'mongoose-paginate-v2';
|
||||
import { Attachment, AttachmentSchema } from './attachment.entity';
|
||||
import { Option, OptionSchema } from './option.entity';
|
||||
import { Attachment, AttachmentSchema } from '../../attachment/entity/attachment.entity';
|
||||
import { Option, OptionSchema } from '../../option/entity/option.entity';
|
||||
|
||||
@Schema({ _id: false, id: false }) // Disable _id and virtual id
|
||||
export class Question extends BaseEntity {
|
||||
|
|
@ -16,11 +16,10 @@ export class Question extends BaseEntity {
|
|||
@Prop({
|
||||
type: String,
|
||||
required: true,
|
||||
// Example types: 'multiple-choice', 'text', 'rating', etc.
|
||||
enum: ['multiple-choice', 'single-choice', 'text', 'rating', 'file'],
|
||||
enum: ['multiple-choice', 'single-choice', 'text'],
|
||||
default: 'text',
|
||||
})
|
||||
type: string;
|
||||
type: 'multiple-choice' | 'single-choice' | 'text';
|
||||
|
||||
@Prop({
|
||||
type: Boolean,
|
||||
|
|
@ -34,7 +33,7 @@ export class Question extends BaseEntity {
|
|||
default: false,
|
||||
required: true,
|
||||
})
|
||||
isConfidential: boolean;
|
||||
isConfidential: boolean; // no real-time updates for normal users
|
||||
|
||||
@Prop({
|
||||
type: String,
|
||||
|
|
|
|||
|
|
@ -30,11 +30,6 @@ export class QuestionService {
|
|||
private readonly questionModel: PaginateModel<QuestionDocument>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a new question.
|
||||
* @param data - The data to create the question with.
|
||||
* @returns The newly created question.
|
||||
*/
|
||||
async create(data: CreateQuestionDto): Promise<Question> {
|
||||
const question = new this.questionModel({
|
||||
...data,
|
||||
|
|
@ -44,12 +39,6 @@ export class QuestionService {
|
|||
return question.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all questions with pagination.
|
||||
* @param page - The current page number.
|
||||
* @param limit - The number of items per page.
|
||||
* @returns A paginated list of questions.
|
||||
*/
|
||||
async findAll(
|
||||
page = 1,
|
||||
limit = 10,
|
||||
|
|
@ -73,11 +62,6 @@ export class QuestionService {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a single question by its UUID.
|
||||
* @param id - The UUID of the question.
|
||||
* @returns The found question or null.
|
||||
*/
|
||||
async findById(id: string): Promise<Question | null> {
|
||||
const selectFields =
|
||||
'id text type isRequired isConfidential validationRules options attachments metadata status createdAt updatedAt';
|
||||
|
|
@ -92,12 +76,6 @@ export class QuestionService {
|
|||
return question;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a question by its UUID.
|
||||
* @param id - The UUID of the question to update.
|
||||
* @param data - The data to update the question with.
|
||||
* @returns The updated question or null.
|
||||
*/
|
||||
async update(
|
||||
id: string,
|
||||
data: UpdateQuestionDto,
|
||||
|
|
@ -120,10 +98,6 @@ export class QuestionService {
|
|||
return updatedQuestion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a question by its UUID.
|
||||
* @param id - The UUID of the question to remove.
|
||||
*/
|
||||
async remove(id: string): Promise<void> {
|
||||
const result = await this.questionModel.deleteOne({ id }).exec();
|
||||
if (result.deletedCount === 0) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue