before adding token
This commit is contained in:
parent
64796fcdf7
commit
d2e3063094
|
|
@ -1,9 +1,24 @@
|
||||||
import { IsString, IsEnum, IsOptional, IsUUID, ValidateNested } from 'class-validator';
|
import { IsEnum, IsOptional, IsUUID, ValidateNested, IsArray, IsString } from 'class-validator';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { MetadataDto } from './metadataEntry.dto';
|
|
||||||
|
export class MetadataEntryDto {
|
||||||
|
@IsString()
|
||||||
|
key: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MetadataDto {
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => MetadataEntryDto)
|
||||||
|
@IsOptional()
|
||||||
|
entries?: { key: string; value: string }[];
|
||||||
|
}
|
||||||
|
|
||||||
export class BaseDto {
|
export class BaseDto {
|
||||||
@IsUUID()
|
@IsUUID('4')
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { IsString, ValidateNested } from 'class-validator';
|
|
||||||
import { Type } from 'class-transformer';
|
|
||||||
|
|
||||||
class MetadataEntryDto {
|
|
||||||
@IsString()
|
|
||||||
key: string;
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MetadataDto {
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => MetadataEntryDto)
|
|
||||||
entries: MetadataEntryDto[];
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
import { Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn, BeforeInsert } from 'typeorm';
|
import { Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn, BeforeInsert } from 'typeorm';
|
||||||
import { Metadata } from './_metadata.entity';
|
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
export class Metadata {
|
||||||
|
@Column({ type: 'jsonb', nullable: true, default: () => "'[]'" })
|
||||||
|
entries?: { key: string; value: string }[];
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class BaseEntity {
|
export abstract class BaseEntity {
|
||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -13,7 +17,7 @@ export abstract class BaseEntity {
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|
||||||
@Column(() => Metadata)
|
@Column(() => Metadata)
|
||||||
metadata: Metadata = new Metadata();
|
metadata?: Metadata;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
|
|
@ -28,5 +32,4 @@ export abstract class BaseEntity {
|
||||||
this.id = uuidv4();
|
this.id = uuidv4();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import { Column, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
@Entity({ name: 'metadata' })
|
|
||||||
export class Metadata {
|
|
||||||
@Column({
|
|
||||||
type: 'uuid',
|
|
||||||
primary: true,
|
|
||||||
default: () => 'uuid_generate_v4()',
|
|
||||||
})
|
|
||||||
id?: string;
|
|
||||||
|
|
||||||
@Column({
|
|
||||||
type: 'jsonb',
|
|
||||||
default: () => "'[]'",
|
|
||||||
})
|
|
||||||
entries?: { key: string; value: string }[];
|
|
||||||
}
|
|
||||||
|
|
@ -14,21 +14,14 @@ export class AnswerService {
|
||||||
|
|
||||||
async create(data: CreateAnswerDto): Promise<Answer> {
|
async create(data: CreateAnswerDto): Promise<Answer> {
|
||||||
try {
|
try {
|
||||||
const answer = this.answerRepository.create({
|
const answer = this.answerRepository.create({ ...data });
|
||||||
...data,
|
|
||||||
metadata: data.metadata || { entries: [] },
|
|
||||||
status: data.status || 'active',
|
|
||||||
});
|
|
||||||
return await this.answerRepository.save(answer);
|
return await this.answerRepository.save(answer);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Failed to create answer: ${error.message}`);
|
throw new Error(`Failed to create answer: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(
|
async findAll( page = 1, limit = 10 ): Promise<{
|
||||||
page = 1,
|
|
||||||
limit = 10,
|
|
||||||
): Promise<{
|
|
||||||
docs: Answer[];
|
docs: Answer[];
|
||||||
totalDocs: number;
|
totalDocs: number;
|
||||||
limit: number;
|
limit: number;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ import { IsString, IsUUID } from 'class-validator';
|
||||||
import { BaseDto } from '../../_core/dto/base.dto';
|
import { BaseDto } from '../../_core/dto/base.dto';
|
||||||
|
|
||||||
export class CreateAnswerDto extends BaseDto {
|
export class CreateAnswerDto extends BaseDto {
|
||||||
@IsUUID()
|
@IsUUID('4')
|
||||||
participantId: string;
|
participantId: string;
|
||||||
|
|
||||||
@IsUUID()
|
@IsUUID('4')
|
||||||
questionId: string;
|
questionId: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { IsEnum, IsOptional, IsString, IsUrl, IsUUID, ValidateNested } from 'class-validator';
|
import { IsEnum, IsOptional, IsString, IsUrl, IsUUID } from 'class-validator';
|
||||||
import { Type } from 'class-transformer';
|
|
||||||
import { BaseDto } from '../../_core/dto/base.dto';
|
import { BaseDto } from '../../_core/dto/base.dto';
|
||||||
|
|
||||||
export class CreateAttachmentDto extends BaseDto {
|
export class CreateAttachmentDto extends BaseDto {
|
||||||
|
|
@ -15,6 +14,6 @@ export class CreateAttachmentDto extends BaseDto {
|
||||||
@IsUrl()
|
@IsUrl()
|
||||||
storageUrl: string;
|
storageUrl: string;
|
||||||
|
|
||||||
@IsUUID()
|
@IsUUID('4')
|
||||||
ownerId: string;
|
ownerId: string;
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// src/config/database.config.ts
|
// src/config/database.config.ts
|
||||||
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||||
import { Participant } from '../participant/entity/participant.entity';
|
import { Participant } from '../participant/entity/participant.entity';
|
||||||
import { Metadata } from '../_core/entity/_metadata.entity';
|
|
||||||
import { Form } from '../form/entity/form.entity';
|
import { Form } from '../form/entity/form.entity';
|
||||||
import { Realm } from '../realm/entity/realm.entity';
|
import { Realm } from '../realm/entity/realm.entity';
|
||||||
import { Question } from '../question/entity/question.entity';
|
import { Question } from '../question/entity/question.entity';
|
||||||
|
|
@ -12,7 +11,7 @@ import { FormSection } from '../formSection/entity/formSection.entity';
|
||||||
import { FormPage } from '../formPage/entity/formPage.entity';
|
import { FormPage } from '../formPage/entity/formPage.entity';
|
||||||
import { FormResult } from '../formResult/entity/formResult.entity';
|
import { FormResult } from '../formResult/entity/formResult.entity';
|
||||||
import { ParticipantGroup } from '../participantGroup/entity/participantGroup.entity';
|
import { ParticipantGroup } from '../participantGroup/entity/participantGroup.entity';
|
||||||
import { BaseEntity } from '../_core/entity/_base.entity';
|
import { BaseEntity, Metadata } from '../_core/entity/_base.entity';
|
||||||
|
|
||||||
export const typeOrmConfig: TypeOrmModuleOptions = {
|
export const typeOrmConfig: TypeOrmModuleOptions = {
|
||||||
type: 'postgres',
|
type: 'postgres',
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class CreateOpinionDto {
|
||||||
@Type(() => CreateOptionsDto)
|
@Type(() => CreateOptionsDto)
|
||||||
options: CreateOptionsDto;
|
options: CreateOptionsDto;
|
||||||
|
|
||||||
@IsUUID()
|
@IsUUID('4')
|
||||||
questionId: string;
|
questionId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ export class Opinion {
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class FormResult extends BaseEntity {
|
export class FormResult extends BaseEntity {
|
||||||
@OneToOne(() => Form, form => form.formResult, { /*cascade: true, eager: true */})
|
@Column({ type: 'uuid' })
|
||||||
form: Form;
|
formId: string;
|
||||||
|
|
||||||
@Column({ type: 'int', default: 0 })
|
@Column({ type: 'int', default: 0 })
|
||||||
numParticipants: number;
|
numParticipants: number;
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,10 @@ export class FormResultController {
|
||||||
return this.formResultService.remove(id);
|
return this.formResultService.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('form/:formId/statistics')
|
// @Get('form/:formId/statistics')
|
||||||
async getFormStatistics(
|
// async getFormStatistics(
|
||||||
@Param('formId', new ParseUUIDPipe()) formId: string,
|
// @Param('formId', new ParseUUIDPipe()) formId: string,
|
||||||
): Promise<FormResult> {
|
// ): Promise<FormResult> {
|
||||||
return this.formResultService.getFormStatistics(formId);
|
// return this.formResultService.getFormStatistics(formId);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
@ -94,90 +94,90 @@ export class FormResultService {
|
||||||
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
async getFormStatistics(formId: string): Promise<FormResult> {
|
// async getFormStatistics(formId: string): Promise<FormResult> {
|
||||||
// 1. Find the Form entity
|
// // 1. Find the Form entity
|
||||||
const form = await this.formRepository.findOne({ where: { id: formId } });
|
// const form = await this.formRepository.findOne({ where: { id: formId } });
|
||||||
if (!form) {
|
// if (!form) {
|
||||||
throw new NotFoundException(`Form with ID "${formId}" not found`);
|
// throw new NotFoundException(`Form with ID "${formId}" not found`);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 2. Compute numQuestions
|
// // 2. Compute numQuestions
|
||||||
const numQuestions = await this.questionRepository.count({
|
// const numQuestions = await this.questionRepository.count({
|
||||||
where: {
|
// where: {
|
||||||
formSection: {
|
// formSection: {
|
||||||
formPage: {
|
// formPage: {
|
||||||
form: { id: formId },
|
// form: { id: formId },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
// 3. Compute numParticipants
|
// // 3. Compute numParticipants
|
||||||
const numParticipantsResult = await this.answerRepository
|
// const numParticipantsResult = await this.answerRepository
|
||||||
.createQueryBuilder('answer')
|
// .createQueryBuilder('answer')
|
||||||
.select('COUNT(DISTINCT answer.participantId)', 'count')
|
// .select('COUNT(DISTINCT answer.participantId)', 'count')
|
||||||
.innerJoin('answer.question', 'question')
|
// .innerJoin('answer.question', 'question')
|
||||||
.innerJoin('question.formSection', 'formSection')
|
// .innerJoin('question.formSection', 'formSection')
|
||||||
.innerJoin('formSection.formPage', 'formPage')
|
// .innerJoin('formSection.formPage', 'formPage')
|
||||||
.where('formPage.formId = :formId', { formId })
|
// .where('formPage.formId = :formId', { formId })
|
||||||
.getRawOne();
|
// .getRawOne();
|
||||||
const numParticipants = numParticipantsResult ? Number(numParticipantsResult.count) : 0;
|
// const numParticipants = numParticipantsResult ? Number(numParticipantsResult.count) : 0;
|
||||||
|
//
|
||||||
// 4. Compute numAnswers
|
// // 4. Compute numAnswers
|
||||||
const numAnswers = await this.answerRepository.count({
|
// const numAnswers = await this.answerRepository.count({
|
||||||
where: {
|
// where: {
|
||||||
question: {
|
// question: {
|
||||||
formSection: {
|
// formSection: {
|
||||||
formPage: {
|
// formPage: {
|
||||||
form: { id: formId },
|
// form: { id: formId },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
// 5. Compute numCompleteParticipants
|
// // 5. Compute numCompleteParticipants
|
||||||
const subQuery = this.answerRepository
|
// const subQuery = this.answerRepository
|
||||||
.createQueryBuilder('answer')
|
// .createQueryBuilder('answer')
|
||||||
.select('answer.participantId')
|
// .select('answer.participantId')
|
||||||
.innerJoin('answer.question', 'question')
|
// .innerJoin('answer.question', 'question')
|
||||||
.innerJoin('question.formSection', 'formSection')
|
// .innerJoin('question.formSection', 'formSection')
|
||||||
.innerJoin('formSection.formPage', 'formPage')
|
// .innerJoin('formSection.formPage', 'formPage')
|
||||||
.where('formPage.formId = :formId', { formId })
|
// .where('formPage.formId = :formId', { formId })
|
||||||
.groupBy('answer.participantId')
|
// .groupBy('answer.participantId')
|
||||||
.having('COUNT(DISTINCT answer.questionId) = :numQuestions', { numQuestions });
|
// .having('COUNT(DISTINCT answer.questionId) = :numQuestions', { numQuestions });
|
||||||
|
//
|
||||||
const numCompleteParticipantsResult = await this.answerRepository.manager
|
// const numCompleteParticipantsResult = await this.answerRepository.manager
|
||||||
.createQueryBuilder()
|
// .createQueryBuilder()
|
||||||
.select('COUNT(*)', 'count')
|
// .select('COUNT(*)', 'count')
|
||||||
.from(`(${subQuery.getQuery()})`, 'subquery')
|
// .from(`(${subQuery.getQuery()})`, 'subquery')
|
||||||
.setParameters(subQuery.getParameters())
|
// .setParameters(subQuery.getParameters())
|
||||||
.getRawOne();
|
// .getRawOne();
|
||||||
const numCompleteParticipants = numCompleteParticipantsResult ? Number(numCompleteParticipantsResult.count) : 0;
|
// const numCompleteParticipants = numCompleteParticipantsResult ? Number(numCompleteParticipantsResult.count) : 0;
|
||||||
|
//
|
||||||
// 6. Find or create FormResult for the Form
|
// // 6. Find or create FormResult for the Form
|
||||||
let formResult = await this.formResultRepo.findOne({ where: { form: { id: formId } }, relations: ['form'] });
|
// let formResult = await this.formResultRepo.findOne({ where: { form: { id: formId } }, relations: ['form'] });
|
||||||
if (!formResult) {
|
// if (!formResult) {
|
||||||
formResult = this.formResultRepo.create({
|
// formResult = this.formResultRepo.create({
|
||||||
form, // Link to the Form entity
|
// form, // Link to the Form entity
|
||||||
numQuestions,
|
// numQuestions,
|
||||||
numParticipants,
|
// numParticipants,
|
||||||
numAnswers,
|
// numAnswers,
|
||||||
numComplete: numCompleteParticipants,
|
// numComplete: numCompleteParticipants,
|
||||||
opinions: [], // Initialize as empty or compute if needed
|
// opinions: [], // Initialize as empty or compute if needed
|
||||||
status: 'active',
|
// status: 'active',
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
formResult.numQuestions = numQuestions;
|
// formResult.numQuestions = numQuestions;
|
||||||
formResult.numParticipants = numParticipants;
|
// formResult.numParticipants = numParticipants;
|
||||||
formResult.numAnswers = numAnswers;
|
// formResult.numAnswers = numAnswers;
|
||||||
formResult.numComplete = numCompleteParticipants;
|
// formResult.numComplete = numCompleteParticipants;
|
||||||
// Preserve existing opinions or update if needed
|
// // Preserve existing opinions or update if needed
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 7. Save and return the FormResult
|
// // 7. Save and return the FormResult
|
||||||
return await this.formResultRepo.save(formResult);
|
// return await this.formResultRepo.save(formResult);
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ export class RealmService {
|
||||||
displayName: data.title + ' Owner', // Default displayName
|
displayName: data.title + ' Owner', // Default displayName
|
||||||
role: 'admin', // Default role for owner
|
role: 'admin', // Default role for owner
|
||||||
userId: decodedToken.sub,
|
userId: decodedToken.sub,
|
||||||
metadata: data.metadata ? { entries: data.metadata.entries } : { entries: [] },
|
metadata: data.metadata ,
|
||||||
// status: 'active',
|
// status: 'active',
|
||||||
});
|
});
|
||||||
participant = await this.participantRepo.save(participant);
|
participant = await this.participantRepo.save(participant);
|
||||||
|
|
@ -58,7 +58,7 @@ export class RealmService {
|
||||||
// Create the realm with the participant as the owner
|
// Create the realm with the participant as the owner
|
||||||
const realm = this.realmRepo.create({
|
const realm = this.realmRepo.create({
|
||||||
...data,
|
...data,
|
||||||
owner: participant, // Set owner to the participant with userId = sub
|
ownerId: participant.userId, // Set owner to the participant with userId = sub
|
||||||
});
|
});
|
||||||
|
|
||||||
return await this.realmRepo.save(realm);
|
return await this.realmRepo.save(realm);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue