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
270 changes: 20 additions & 250 deletions src/iq-assessment/controllers/iq-assessment.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,322 +50,95 @@ export class IQAssessmentController {
constructor(
private readonly iqAssessmentService: IQAssessmentService,
private readonly iqAttemptService: IqAttemptService,
private readonly svc: IQAssessmentService,
) {}

@Post('sessions')
@HttpCode(HttpStatus.CREATED)
@ApiOperation({ summary: 'Start a new IQ assessment session' })
@ApiBody({ type: CreateSessionDto })
@ApiResponse({
status: HttpStatus.CREATED,
description: 'Session created successfully',
type: SessionResponseDto,
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description:
'User already has an active session or not enough questions available',
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'User not found',
})
async createSession(
createSessionDto: CreateSessionDto,
): Promise<SessionResponseDto> {
console.log('Received createSessionDto:', createSessionDto);
@ApiResponse({ status: HttpStatus.CREATED, description: 'Session created successfully', type: SessionResponseDto })
async createSession(@Body() createSessionDto: CreateSessionDto): Promise<SessionResponseDto> {
return this.iqAssessmentService.createSession(createSessionDto);
}

@Get('sessions/:sessionId')
@ApiOperation({ summary: 'Get current session progress and next question' })
@ApiParam({ name: 'sessionId', description: 'Session UUID' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Session progress retrieved successfully',
type: SessionResponseDto,
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Session not found',
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: 'Session is already completed',
})
async getSessionProgress(
@Param('sessionId', ParseUUIDPipe) sessionId: string,
): Promise<SessionResponseDto> {
async getSessionProgress(@Param('sessionId', ParseUUIDPipe) sessionId: string): Promise<SessionResponseDto> {
return this.iqAssessmentService.getSessionProgress(sessionId);
}

@Post('sessions/submit-answer')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Submit an answer for a question' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Answer submitted successfully',
type: SessionResponseDto,
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Session or question not found',
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description:
'Session completed or answer already submitted for this question',
})
async submitAnswer(
submitAnswerDto: SubmitAnswerDto,
): Promise<SessionResponseDto> {
async submitAnswer(@Body() submitAnswerDto: SubmitAnswerDto): Promise<SessionResponseDto> {
return this.iqAssessmentService.submitAnswer(submitAnswerDto);
}

@Post('sessions/complete')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Complete an assessment session' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Session completed successfully',
type: CompletedSessionResponseDto,
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Session not found',
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: 'Session is already completed',
})
async completeSession(
completeSessionDto: CompleteSessionDto,
): Promise<CompletedSessionResponseDto> {
return this.iqAssessmentService.completeSession(
completeSessionDto.sessionId,
);
async completeSession(@Body() completeSessionDto: CompleteSessionDto): Promise<CompletedSessionResponseDto> {
return this.iqAssessmentService.completeSession(completeSessionDto.sessionId);
}

@Post('sessions/:sessionId/skip/:questionId')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Skip a question' })
@ApiParam({ name: 'sessionId', description: 'Session UUID' })
@ApiParam({ name: 'questionId', description: 'Question UUID' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Question skipped successfully',
type: SessionResponseDto,
})
async skipQuestion(
@Param('sessionId', ParseUUIDPipe) sessionId: string,
@Param('questionId', ParseUUIDPipe) questionId: string,
): Promise<SessionResponseDto> {
async skipQuestion(@Param('sessionId', ParseUUIDPipe) sessionId: string, @Param('questionId', ParseUUIDPipe) questionId: string): Promise<SessionResponseDto> {
return this.iqAssessmentService.skipQuestion(sessionId, questionId);
}

@Get('users/:userId/sessions')
@ApiOperation({ summary: 'Get all sessions for a user' })
@ApiParam({ name: 'userId', description: 'User ID' })
@ApiResponse({
status: HttpStatus.OK,
description: 'User sessions retrieved successfully',
})
async getUserSessions(@Param('userId', ParseIntPipe) userId: string) {
return this.iqAssessmentService.getUserSessions(userId);
}

@Get('sessions/:sessionId/details')
@ApiOperation({ summary: 'Get detailed session information' })
@ApiParam({ name: 'sessionId', description: 'Session UUID' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Session details retrieved successfully',
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Session not found',
})
async getSessionDetails(
@Param('sessionId', ParseUUIDPipe) sessionId: string,
) {
async getSessionDetails(@Param('sessionId', ParseUUIDPipe) sessionId: string) {
return this.iqAssessmentService.getSessionById(sessionId);
}

@Get('external/random')
async getOneExternal() {
const questions: ExternalIQQuestion[] =
await this.svc.fetchExternalQuestions(1);
const [q] = questions;
return q;
const questions = await this.iqAssessmentService.fetchExternalQuestions(1);
return questions[0];
}

// New Attempt Analytics Endpoints

@Get('attempts/users/:userId')
@ApiOperation({ summary: 'Get all attempts for a specific user' })
@ApiParam({ name: 'userId', description: 'User UUID' })
@ApiResponse({
status: HttpStatus.OK,
description: 'User attempts retrieved successfully',
type: [AttemptResponseDto],
})
async getUserAttempts(
@Param('userId', ParseUUIDPipe) userId: string,
): Promise<AttemptResponseDto[]> {
async getUserAttempts(@Param('userId', ParseUUIDPipe) userId: string): Promise<AttemptResponseDto[]> {
return this.iqAttemptService.findAllByUser(userId);
}

@Get('attempts/users/:userId/stats')
@ApiOperation({ summary: 'Get attempt statistics for a specific user' })
@ApiParam({ name: 'userId', description: 'User UUID' })
@ApiResponse({
status: HttpStatus.OK,
description: 'User attempt statistics retrieved successfully',
type: UserAttemptsStatsDto,
})
async getUserAttemptStats(
@Param('userId', ParseUUIDPipe) userId: string,
): Promise<UserAttemptsStatsDto> {
async getUserAttemptStats(@Param('userId', ParseUUIDPipe) userId: string): Promise<UserAttemptsStatsDto> {
return this.iqAttemptService.getUserStats(userId);
}

@Get('attempts/questions/:questionId')
@ApiOperation({ summary: 'Get all attempts for a specific question' })
@ApiParam({ name: 'questionId', description: 'Question UUID' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Question attempts retrieved successfully',
type: [AttemptResponseDto],
})
async getQuestionAttempts(
@Param('questionId', ParseUUIDPipe) questionId: string,
): Promise<AttemptResponseDto[]> {
async getQuestionAttempts(@Param('questionId', ParseUUIDPipe) questionId: string): Promise<AttemptResponseDto[]> {
return this.iqAttemptService.findAllByQuestion(questionId);
}

@Get('attempts/recent')
@ApiOperation({ summary: 'Get recent attempts for analytics' })
@ApiQuery({
name: 'limit',
required: false,
description: 'Number of attempts to return (default: 100)',
})
@ApiResponse({
status: HttpStatus.OK,
description: 'Recent attempts retrieved successfully',
type: [AttemptResponseDto],
})
async getRecentAttempts(
@Query('limit') limit?: number,
): Promise<AttemptResponseDto[]> {
async getRecentAttempts(@Query('limit') limit?: number): Promise<AttemptResponseDto[]> {
return this.iqAttemptService.getRecentAttempts(limit);
}

@Get('attempts/stats/global')
@ApiOperation({ summary: 'Get global attempt statistics' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Global statistics retrieved successfully',
})
async getGlobalStats() {
return this.iqAttemptService.getGlobalStats();
}

@Get('attempts/date-range')
@ApiOperation({ summary: 'Get attempts within a date range' })
@ApiQuery({ name: 'startDate', description: 'Start date (ISO string)' })
@ApiQuery({ name: 'endDate', description: 'End date (ISO string)' })
@ApiQuery({
name: 'userId',
required: false,
description: 'Filter by user ID',
})
@ApiResponse({
status: HttpStatus.OK,
description: 'Attempts retrieved successfully',
type: [AttemptResponseDto],
})
async getAttemptsByDateRange(
@Query('startDate') startDate: string,
@Query('endDate') endDate: string,
@Query('userId') userId?: string,
): Promise<AttemptResponseDto[]> {
return this.iqAttemptService.getAttemptsByDateRange(
new Date(startDate),
new Date(endDate),
userId,
);
async getAttemptsByDateRange(@Query('startDate') startDate: string, @Query('endDate') endDate: string, @Query('userId') userId?: string): Promise<AttemptResponseDto[]> {
return this.iqAttemptService.getAttemptsByDateRange(new Date(startDate), new Date(endDate), userId);
}

@Post('submit')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Submit a standalone answer for a question' })
@ApiBody({ type: StandaloneSubmitAnswerDto })
@ApiResponse({
status: HttpStatus.OK,
description: 'Answer submitted successfully',
type: AnswerSubmissionResponseDto,
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Question not found',
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: 'Invalid request data',
})
async submitStandaloneAnswer(
@Body() submitAnswerDto: StandaloneSubmitAnswerDto,
): Promise<AnswerSubmissionResponseDto> {
async submitStandaloneAnswer(@Body() submitAnswerDto: StandaloneSubmitAnswerDto): Promise<AnswerSubmissionResponseDto> {
return this.iqAssessmentService.submitStandaloneAnswer(submitAnswerDto);
}

@Get('questions/random')
@ApiOperation({ summary: 'Get random questions with optional filtering' })
@ApiQuery({
name: 'difficulty',
required: false,
enum: ['easy', 'medium', 'hard'],
})
@ApiQuery({
name: 'category',
required: false,
enum: [
'Science',
'Mathematics',
'Logic',
'Language',
'History',
'Geography',
'Literature',
'Art',
'Sports',
'Entertainment',
'General Knowledge',
],
})
@ApiQuery({
name: 'count',
required: false,
type: Number,
minimum: 1,
maximum: 50,
})
@ApiResponse({
status: HttpStatus.OK,
description: 'Random questions retrieved successfully',
type: [RandomQuestionResponseDto],
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: 'Invalid filter parameters',
})
async getRandomQuestions(
@Query() queryDto: RandomQuestionsQueryDto,
): Promise<RandomQuestionResponseDto[]> {
const questions =
await this.iqAssessmentService.getRandomQuestionsWithFilters(queryDto);
async getRandomQuestions(@Query() queryDto: RandomQuestionsQueryDto): Promise<RandomQuestionResponseDto[]> {
const questions = await this.iqAssessmentService.getRandomQuestionsWithFilters(queryDto);
return questions.map((question) => ({
id: question.id,
questionText: question.questionText,
Expand All @@ -376,10 +149,7 @@ export class IQAssessmentController {
}

@Post('submit')
async submitQuiz(
@ActiveUser() user: ActiveUserData,
@Body() dto: SubmitQuizDto,
) {
async submitQuiz(@ActiveUser() user: ActiveUserData, @Body() dto: SubmitQuizDto) {
return this.iqAssessmentService.submitQuiz(user, dto);
}
}
Loading
Loading