Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions backend/src/quizzes/entities/quiz.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ export class Quiz {
@Column()
passingScore: number;

@Column()
timeLimit: number;

@Column()
@Column({ type: 'int', default: 1 })
maxAttempts: number;

@Column({ type: 'int', nullable: true })
timeLimit: number;

@OneToMany(() => QuizQuestion, (quizQuestion) => quizQuestion.quiz)
questions: QuizQuestion[];

Expand Down
121 changes: 112 additions & 9 deletions backend/src/quizzes/quizzes.service.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,129 @@
import { Injectable } from '@nestjs/common';
import {
Injectable,
ForbiddenException,
NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Quiz } from './entities/quiz.entity';
import { CreateQuizDto } from './dto/create-quiz.dto';
import { UpdateQuizDto } from './dto/update-quiz.dto';
import { SubmitQuizAttemptDto } from './dto/submit-quiz-attempt.dto';
import { QuizAttempt } from './entities/quiz-attempt.entity';

@Injectable()
export class QuizzesService {
constructor(
@InjectRepository(Quiz)
private readonly quizRepo: Repository<Quiz>,

@InjectRepository(QuizAttempt)
private readonly submissionRepo: Repository<QuizAttempt>,
) {}

// Create a new quiz
create(createQuizDto: CreateQuizDto) {
return 'This action adds a new quiz';
const quiz = this.quizRepo.create(createQuizDto);
return this.quizRepo.save(quiz);
}

// Get all quizzes
findAll() {
return `This action returns all quizzes`;
return this.quizRepo.find();
}

// Get a single quiz
async findOne(id: number) {
const quiz = await this.quizRepo.findOne({ where: { id } });
if (!quiz) throw new NotFoundException('Quiz not found');
return quiz;
}

// Update a quiz
async update(id: number, updateQuizDto: UpdateQuizDto) {
await this.quizRepo.update(id, updateQuizDto);
return this.findOne(id);
}

// Delete a quiz
async remove(id: number) {
await this.quizRepo.delete(id);
return { message: 'Quiz deleted' };
}

findOne(id: number) {
return `This action returns a #${id} quiz`;
// Validate user's quiz submission
async validateQuizSubmission(
userId: string,
quizId: string | number,
submissionId?: string,
) {
const quiz = await this.quizRepo.findOne({ where: { id: Number(quizId) } });

if (!quiz) throw new NotFoundException('Quiz not found');

const attempts = await this.submissionRepo.count({
where: { userId: String(userId), quizId: String(quizId) },
});
if (attempts >= quiz.maxAttempts) {
throw new ForbiddenException('Max attempts exceeded');
}

if (submissionId) {
const submission = await this.submissionRepo.findOne({
where: { id: submissionId },
});
if (!submission) throw new NotFoundException('Submission not found');

const elapsed =
(new Date().getTime() - new Date(submission.startTime).getTime()) /
1000;
if (quiz.timeLimit && elapsed > quiz.timeLimit) {
throw new ForbiddenException('Time limit exceeded');
}
}
}

update(id: number, updateQuizDto: UpdateQuizDto) {
return `This action updates a #${id} quiz`;
// Handle quiz submission
async submitQuizAttempt(submissionId: string, dto: SubmitQuizAttemptDto) {
const submission = await this.submissionRepo.findOne({
where: { id: submissionId },
relations: ['quiz'],
});

if (!submission) throw new NotFoundException('Submission not found');

const now = new Date();
const elapsed =
(now.getTime() - new Date(submission.startTime).getTime()) / 1000;

if (submission.quiz.timeLimit && elapsed > submission.quiz.timeLimit) {
throw new ForbiddenException('Time limit exceeded');
}

submission.answers = dto.answers;
submission.endTime = now;

return this.submissionRepo.save(submission);
}

remove(id: number) {
return `This action removes a #${id} quiz`;
async startQuizAttempt(userId: string, quizId: string) {
const quiz = await this.quizRepo.findOne({ where: { id: Number(quizId) } });
if (!quiz) throw new NotFoundException('Quiz not found');

const attempts = await this.submissionRepo.count({
where: { userId, quizId },
});
if (attempts >= quiz.maxAttempts) {
throw new ForbiddenException('Max attempts exceeded');
}

const submission = this.submissionRepo.create({
userId,
quizId,
attemptNumber: attempts + 1,
startTime: new Date(),
});

return this.submissionRepo.save(submission);
}
}
Loading