Files
reloop-v2/backend/src/problem-sets/problem-sets.controller.ts
reloop 58719e329e feat: 문제풀이 UI 통일 + PDF→문제집 + 통계탭 삭제
- 통계 탭 삭제 (프론트 페이지/차트/네비 항목, 백엔드 stats 모듈은 대시보드용으로 유지)
- PDF 문제 분리 → 문제집 생성으로 변경 (ProblemSet + Problem 레코드)
  - ProblemSet에 sourceType, uploadedByUserId 추가
  - POST /problem-sets/create-from-pdf 엔드포인트
  - GET /problem-sets/my-uploads, DELETE /problem-sets/:id
  - exams 페이지에 '내가 만든 문제집' 섹션
- 문제 풀이 UI 통일
  - DrawingCanvas 공통 컴포넌트 추출 (필기모드)
  - 복습 페이지에 필기모드(캔버스+펜색상) 추가
  - 다시풀기 페이지에 필기모드+메모 추가
  - 처음풀기 페이지 난이도 슬라이더→3버튼(H/M/E)+SM-2 연동

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 10:17:12 +09:00

112 lines
2.0 KiB
TypeScript

import {
Body,
Controller,
Delete,
Get,
Param,
ParseIntPipe,
Post,
Query,
UseGuards,
} from '@nestjs/common';
import {
IsArray,
IsInt,
IsNumber,
IsOptional,
IsString,
Max,
Min,
ValidateNested,
} from 'class-validator';
import { Type } from 'class-transformer';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { CurrentUser } from '../auth/current-user.decorator';
import { AuthUser } from '../auth/jwt.strategy';
import { ProblemSetsService } from './problem-sets.service';
class ListProblemSetsQuery {
@IsOptional()
@IsString()
subjectName?: string;
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1900)
@Max(2100)
year?: number;
}
class CreateFromPdfProblemDto {
@IsInt()
number: number;
@IsString()
imageUrl: string;
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
@Max(5)
correctAnswer?: number;
@IsOptional()
@IsNumber()
@Min(0)
@Max(1)
difficulty?: number;
}
class CreateFromPdfDto {
@IsString()
title: string;
@IsOptional()
@IsString()
subjectName?: string;
@IsArray()
@ValidateNested({ each: true })
@Type(() => CreateFromPdfProblemDto)
problems: CreateFromPdfProblemDto[];
}
@Controller('problem-sets')
@UseGuards(JwtAuthGuard)
export class ProblemSetsController {
constructor(private readonly svc: ProblemSetsService) {}
@Get()
list(@Query() q: ListProblemSetsQuery) {
return this.svc.list(q);
}
@Get('my-uploads')
myUploads(@CurrentUser() user: AuthUser) {
return this.svc.listMyUploads(user.id);
}
@Get(':id')
one(@Param('id', ParseIntPipe) id: number) {
return this.svc.getOne(id);
}
@Post('create-from-pdf')
createFromPdf(
@CurrentUser() user: AuthUser,
@Body() dto: CreateFromPdfDto,
) {
return this.svc.createFromPdf(user.id, dto);
}
@Delete(':id')
deleteUpload(
@CurrentUser() user: AuthUser,
@Param('id', ParseIntPipe) id: number,
) {
return this.svc.deleteUpload(user.id, id);
}
}