From 07f9b7262824da7b1cc30ea9754be6367b881060 Mon Sep 17 00:00:00 2001 From: JongHwa Paik Date: Mon, 16 Jun 2025 21:20:21 +0900 Subject: [PATCH 1/8] =?UTF-8?q?=F0=9F=90=9B=20fix=20:=20=EC=98=9B=EB=82=A0?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/test/test_router.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/api/v1/test/test_router.py b/api/v1/test/test_router.py index 6403eda..b508f64 100644 --- a/api/v1/test/test_router.py +++ b/api/v1/test/test_router.py @@ -81,16 +81,6 @@ async def submit_today_test( ): return await submit_today_test_usecase(current_user, db) -# 시험 결과 제출 (시험 모드) -@router.post("/submit/{test_id}", response_model=SubmitTestResponse) -async def submit_test( - test_id: str = Path(...), - request: SubmitTestRequest = Depends(), - db: Session = Depends(get_db), - current_user: User = Depends(get_current_user) -): - return await submit_test_usecase(test_id, request, db, current_user) - # 문제 풀기 (쉬엄 모드) @router.get("/rest-mode/{question_count}", response_model=RestModeResponse) async def get_relax_mode_questions( From 2cbcdf4f8e496fd68643b30eef7c2a876621ce44 Mon Sep 17 00:00:00 2001 From: JongHwa Paik Date: Mon, 16 Jun 2025 21:17:26 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=90=9B=20fix=20:=20=EC=98=A4=EB=8A=98?= =?UTF-8?q?=EC=9D=98=20=EB=AC=B8=EC=A0=9C=20=EC=83=9D=EC=84=B1=20=EC=95=88?= =?UTF-8?q?=EB=90=A8=20=EB=AC=B8=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/test/test_router.py | 2 +- app/test/usecase/create_today_test_usecase.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/api/v1/test/test_router.py b/api/v1/test/test_router.py index b508f64..28a3236 100644 --- a/api/v1/test/test_router.py +++ b/api/v1/test/test_router.py @@ -55,7 +55,7 @@ router = APIRouter() # 오늘의 문제 -@router.post("/create-today-questions/{certificate_id}", summary="오늘의 문제 생성 또는 불러오기") +@router.post("/create-today-questions/{certificate_id}", summary="오늘의 문제 생성") async def create_today_questions( certificate_id: int = Path(..., description="자격증 ID"), current_user: User = Depends(get_current_user), diff --git a/app/test/usecase/create_today_test_usecase.py b/app/test/usecase/create_today_test_usecase.py index b5b6fc8..f11188e 100644 --- a/app/test/usecase/create_today_test_usecase.py +++ b/app/test/usecase/create_today_test_usecase.py @@ -159,6 +159,12 @@ async def create_today_questions_usecase(certificate_id: int, current_user: User await db.commit() + result = await db.execute( + select(TodayTestQuestion) + .where(TodayTestQuestion.today_test_by_ai_id == today_test.id) + ) + questions = result.scalars().all() + return ok( data={ "question_count": len(questions), From b6249498861f4859dc6e1e5e42e7e3278eb531eb Mon Sep 17 00:00:00 2001 From: seoiiwon Date: Mon, 16 Jun 2025 21:24:12 +0900 Subject: [PATCH 3/8] =?UTF-8?q?=E2=9C=A8=20feat[#35]:=20certificate=20list?= =?UTF-8?q?=20dto=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/user/dto/response/certificate.py | 6 ++++++ app/user/dto/response/certificates_response.py | 9 +++++++++ app/utils/__init__.py | 0 app/utils/dto/__init__.py | 0 app/utils/dto/pagination.py | 8 ++++++++ 5 files changed, 23 insertions(+) create mode 100644 app/user/dto/response/certificate.py create mode 100644 app/user/dto/response/certificates_response.py create mode 100644 app/utils/__init__.py create mode 100644 app/utils/dto/__init__.py create mode 100644 app/utils/dto/pagination.py diff --git a/app/user/dto/response/certificate.py b/app/user/dto/response/certificate.py new file mode 100644 index 0000000..5c4edb6 --- /dev/null +++ b/app/user/dto/response/certificate.py @@ -0,0 +1,6 @@ +from pydantic import BaseModel + + +class CertificateDto(BaseModel): + certificate_id: str + name: str \ No newline at end of file diff --git a/app/user/dto/response/certificates_response.py b/app/user/dto/response/certificates_response.py new file mode 100644 index 0000000..a9f588d --- /dev/null +++ b/app/user/dto/response/certificates_response.py @@ -0,0 +1,9 @@ +from typing import List +from pydantic import BaseModel +from app.user.dto.response.certificate import CertificateDto +from app.utils.dto.pagination import PaginationDto + + +class CertificateResponseDto(BaseModel): + certificates: List[CertificateDto] + pagination: PaginationDto \ No newline at end of file diff --git a/app/utils/__init__.py b/app/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/utils/dto/__init__.py b/app/utils/dto/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/utils/dto/pagination.py b/app/utils/dto/pagination.py new file mode 100644 index 0000000..c5ddc97 --- /dev/null +++ b/app/utils/dto/pagination.py @@ -0,0 +1,8 @@ +from openai import BaseModel + + +class PaginationDto(BaseModel): + offset: int + limit: int + total_count: int + next_page: bool \ No newline at end of file From aeab841a4bd52da2ecd22853902d62b857d58ac0 Mon Sep 17 00:00:00 2001 From: seoiiwon Date: Mon, 16 Jun 2025 21:33:57 +0900 Subject: [PATCH 4/8] =?UTF-8?q?=E2=9C=A8=20feat[#35]:=20certificate=20list?= =?UTF-8?q?=20repository=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- domain/user/repository/certificate_repository.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/domain/user/repository/certificate_repository.py b/domain/user/repository/certificate_repository.py index 603f0ac..f3d57c6 100644 --- a/domain/user/repository/certificate_repository.py +++ b/domain/user/repository/certificate_repository.py @@ -1,4 +1,6 @@ -from sqlalchemy import Sequence +from typing import List + +from sqlalchemy import Sequence, select from sqlalchemy.ext.asyncio import AsyncSession from domain.user.entity.certificate import Certificate from domain.user.entity.user import User @@ -30,3 +32,14 @@ async def add_user_certificate(db: AsyncSession, user: User, certificates: Seque await db.commit() await db.refresh(user) return user + + + @staticmethod + async def get_certificates_list(db: AsyncSession, offset: int, limit: int) -> (List[Certificate], int): + result = await db.execute( + select(Certificate).offset(offset).limit(limit) + ) + certificates = result.scalars().all() + total_result = await db.execute(select(Certificate)) + total = len(total_result.scalars().all()) + return certificates, total \ No newline at end of file From aa96c08cfddd4d308d76d72ca436e4f83e56e33d Mon Sep 17 00:00:00 2001 From: seoiiwon Date: Mon, 16 Jun 2025 21:38:06 +0900 Subject: [PATCH 5/8] =?UTF-8?q?=E2=9C=A8=20feat[#35]:=20certificate=20list?= =?UTF-8?q?=20service=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- domain/user/service/certificate_service.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 domain/user/service/certificate_service.py diff --git a/domain/user/service/certificate_service.py b/domain/user/service/certificate_service.py new file mode 100644 index 0000000..0f8a0c9 --- /dev/null +++ b/domain/user/service/certificate_service.py @@ -0,0 +1,18 @@ +from typing import List + +from sqlalchemy.ext.asyncio import AsyncSession + +from app.user.dto.response.certificate import CertificateDto +from domain.user.repository.certificate_repository import CertificateRepository + + +class CertificateService: + def __init__(self, repository: CertificateRepository): + self.repository = repository + + async def fetch(self, db: AsyncSession, offset: int, limit: int) -> (List[CertificateDto], int): + certificates, total = await self.repository.get_certificates_list(db, offset, limit) + certificates_list = [ + CertificateDto(certificate_id=certificate.id, name=certificate.name) for certificate in certificates + ] + return certificates_list, total \ No newline at end of file From ebf0d42b266024a9eb6ad4ea822327b1d3c0f75f Mon Sep 17 00:00:00 2001 From: seoiiwon Date: Mon, 16 Jun 2025 22:09:29 +0900 Subject: [PATCH 6/8] =?UTF-8?q?=F0=9F=94=A8=20refactor[#35]:=20certificate?= =?UTF-8?q?=20list=20dto,=20service=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/user/dto/response/certificate.py | 2 +- domain/user/service/certificate_service.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/user/dto/response/certificate.py b/app/user/dto/response/certificate.py index 5c4edb6..cc5e15a 100644 --- a/app/user/dto/response/certificate.py +++ b/app/user/dto/response/certificate.py @@ -2,5 +2,5 @@ class CertificateDto(BaseModel): - certificate_id: str + certificate_id: int name: str \ No newline at end of file diff --git a/domain/user/service/certificate_service.py b/domain/user/service/certificate_service.py index 0f8a0c9..fdfc02a 100644 --- a/domain/user/service/certificate_service.py +++ b/domain/user/service/certificate_service.py @@ -7,11 +7,10 @@ class CertificateService: - def __init__(self, repository: CertificateRepository): - self.repository = repository - async def fetch(self, db: AsyncSession, offset: int, limit: int) -> (List[CertificateDto], int): - certificates, total = await self.repository.get_certificates_list(db, offset, limit) + @staticmethod + async def fetch_certificates(db: AsyncSession, offset: int, limit: int) -> (List[CertificateDto], int): + certificates, total = await CertificateRepository.get_certificates_list(db, offset, limit) certificates_list = [ CertificateDto(certificate_id=certificate.id, name=certificate.name) for certificate in certificates ] From 0ee1b17c20e2d365895fef4ffe7e505a0ffa16b7 Mon Sep 17 00:00:00 2001 From: seoiiwon Date: Mon, 16 Jun 2025 22:10:24 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=E2=9C=A8=20feat[#35]:=20certificate=20list?= =?UTF-8?q?=20router=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/routers.py | 5 +++-- api/v1/user/certificate_router.py | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 api/v1/user/certificate_router.py diff --git a/api/v1/routers.py b/api/v1/routers.py index be62b2d..ddb509f 100644 --- a/api/v1/routers.py +++ b/api/v1/routers.py @@ -2,7 +2,7 @@ from api.v1.review import review_router from api.v1.auth import auth_router -from api.v1.user import user_router +from api.v1.user import user_router, certificate_router from api.v1.studybook import studybook_router from api.v1.studybook import studybook_question_router from api.v1.test import test_router @@ -13,4 +13,5 @@ router.include_router(user_router.router, tags=["user"], prefix="/user") router.include_router(studybook_router.router, tags=["studybook"], prefix="/studybook") router.include_router(studybook_question_router.router, tags=["studybook_question"], prefix="/studybook-question") -router.include_router(test_router.router, tags=["test"], prefix="/test") \ No newline at end of file +router.include_router(test_router.router, tags=["test"], prefix="/test") +router.include_router(certificate_router.router, tags=["certificate"], prefix="/user") \ No newline at end of file diff --git a/api/v1/user/certificate_router.py b/api/v1/user/certificate_router.py new file mode 100644 index 0000000..74c8f9a --- /dev/null +++ b/api/v1/user/certificate_router.py @@ -0,0 +1,23 @@ +from typing import List + +from fastapi import APIRouter, Query, Depends +from sqlalchemy.ext.asyncio import AsyncSession + +from app.user.dto.response.certificates_response import CertificateResponseDto +from app.user.usecase.certificate_usecase import CertificateUseCase +from database.dependency import get_db +from domain.user.repository.certificate_repository import CertificateRepository +from domain.user.service.certificate_service import CertificateService +from exception.success import ok + +router = APIRouter() +@router.get("/get-certificates-list", response_model=CertificateResponseDto) +async def get_certificates_list( + offset: int = Query(0, ge=0), + limit: int = Query(20, ge=0), + db: AsyncSession = Depends(get_db) +): + usecase = CertificateUseCase() + data = await usecase.execute(db=db, offset=offset, limit=limit) + + return ok(data=data.model_dump() ,message="자격증 리스트 조회 성공") \ No newline at end of file From 95abf38ce5514f1b053a978c206f265056d744de Mon Sep 17 00:00:00 2001 From: seoiiwon Date: Mon, 16 Jun 2025 22:10:50 +0900 Subject: [PATCH 8/8] =?UTF-8?q?=F0=9F=94=A8=20refactor[#35]:=20certificate?= =?UTF-8?q?=20list=20usecase=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/user/usecase/certificate_usecase.py | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 app/user/usecase/certificate_usecase.py diff --git a/app/user/usecase/certificate_usecase.py b/app/user/usecase/certificate_usecase.py new file mode 100644 index 0000000..d6506b1 --- /dev/null +++ b/app/user/usecase/certificate_usecase.py @@ -0,0 +1,31 @@ +from typing import List + +from sqlalchemy.ext.asyncio import AsyncSession + +from app.user.dto.response.certificates_response import CertificateResponseDto +from app.utils.dto.pagination import PaginationDto +from domain.user.repository.certificate_repository import CertificateRepository +from domain.user.service.certificate_service import CertificateService +from exception.client_exception import NotFoundException, BadRequestException + + +class CertificateUseCase: + + @staticmethod + async def execute(db: AsyncSession, offset: int, limit: int) -> CertificateResponseDto: + certificates, total = await CertificateService.fetch_certificates(db, offset, limit) + + if offset >= total: + raise BadRequestException(message="더이상 불러올 내용이 없습니다.") + + pagination = PaginationDto( + offset=offset, + limit=limit, + total_count=total, + next_page=(offset + limit < total) + ) + + return CertificateResponseDto( + certificates=certificates, + pagination=pagination + ) \ No newline at end of file