Feat: 리크루팅 지원 결과 api 구현#138
Conversation
mjy926
commented
May 15, 2026
- 특정 recruiting id에 해당하는 지원 결과를 반환하는 api를 구현했습니다.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough모집별 지원자 제출 현황을 한 화면에 표시하기 위해 이력서 답변과 코드 제출 정답 카운트를 집계하는 조회 기능을 추가했습니다. 응답 스키마 정의부터 저장소의 SQL 피벗 쿼리, 서비스 계층 조합, FastAPI 라우트 노출까지 전체 계층을 구현합니다. Changes모집 지원자 제출 현황 조회
🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
wacruit/src/apps/recruiting/repositories.py (1)
357-365: 💤 Low value중복된 coalesce 처리가 있습니다.
라인 302-341의
code_pivot서브쿼리에서 이미func.coalesce(..., 0)로 NULL을 0으로 처리했는데, 라인 357-365의 최종 select에서 다시func.coalesce(code_pivot.c.problem_X_correct, 0)를 적용하고 있습니다. 이는 불필요한 중복입니다.♻️ 제안하는 중복 제거
resume_pivot.c.q1_answer, resume_pivot.c.q2_answer, resume_pivot.c.q3_answer, - func.coalesce(code_pivot.c.problem_1_correct, 0).label( - "problem_1_correct" - ), - func.coalesce(code_pivot.c.problem_2_correct, 0).label( - "problem_2_correct" - ), - func.coalesce(code_pivot.c.problem_3_correct, 0).label( - "problem_3_correct" - ), + code_pivot.c.problem_1_correct, + code_pivot.c.problem_2_correct, + code_pivot.c.problem_3_correct, )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@wacruit/src/apps/recruiting/repositories.py` around lines 357 - 365, The final SELECT redundantly wraps code_pivot's already-coalesced columns with func.coalesce again; remove the extra coalesce calls in the projection and reference code_pivot.c.problem_1_correct, code_pivot.c.problem_2_correct, code_pivot.c.problem_3_correct (etc.) directly while preserving their .label("problem_X_correct") names so the previously-applied coalesce in the code_pivot subquery remains the single source of NULL->0 handling.wacruit/src/apps/recruiting/schemas.py (1)
16-17: 💤 Low value빈 TYPE_CHECKING 블록은 제거를 고려하세요.
TYPE_CHECKING 블록 내부에 실제 임포트가 없다면 블록 전체를 제거하는 것이 더 깔끔합니다.
♻️ 제안하는 정리 방안
-if TYPE_CHECKING: - pass🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@wacruit/src/apps/recruiting/schemas.py` around lines 16 - 17, Remove the empty TYPE_CHECKING block in wacruit/src/apps/recruiting/schemas.py: locate the "if TYPE_CHECKING:" block and delete it (including its pass) since there are no conditional type-only imports; if you later need type-only imports retain TYPE_CHECKING and add the imports inside the block.wacruit/src/apps/recruiting/views_v3.py (1)
88-96: ⚡ Quick win쿼리 파라미터에 검증 제약 조건을 추가하는 것을 고려하세요.
FastAPI의
Query를 사용하면서ge(greater than or equal),le(less than or equal) 등의 제약 조건을 설정하지 않았습니다. 서비스 계층에서 검증할 수도 있지만, API 계층에서 명시하면 자동 문서화와 조기 검증이 가능합니다.📝 제안하는 제약 조건 추가
`@v3_router.get`("/{recruiting_id}/submission") def get_recruiting_submission( admin_user: AdminUser, recruiting_id: int, recruiting_service: Annotated[RecruitingService, Depends()], - limit: int = Query(100), - offset: int = Query(0), + limit: int = Query(100, ge=1, le=1000), + offset: int = Query(0, ge=0), ) -> RecruitingSubmissionListResponse: return recruiting_service.get_recruiting_submissions(recruiting_id, limit, offset)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@wacruit/src/apps/recruiting/views_v3.py` around lines 88 - 96, The get_recruiting_submission endpoint currently declares limit and offset via Query without validation; update the parameter declarations in get_recruiting_submission to add appropriate Query constraints (e.g., limit with ge=1 and a sensible le like 1000, offset with ge=0) so FastAPI performs early validation and documents these bounds; modify the Query(...) calls for the limit and offset parameters used in the get_recruiting_submission function signature to include these ge/le constraints.wacruit/src/apps/recruiting/services.py (1)
283-292: ⚡ Quick winlimit/offset 파라미터 검증이 누락되었습니다.
음수 값이나 비정상적으로 큰 값이 전달될 수 있습니다. 페이징 파라미터에 대한 경계 검증을 추가하는 것이 좋습니다.
🛡️ 제안하는 검증 추가
def get_recruiting_submissions( self, recruiting_id: int, limit: int, offset: int ) -> RecruitingSubmissionListResponse: + if limit <= 0 or limit > 1000: + raise ValueError("Limit must be between 1 and 1000") + if offset < 0: + raise ValueError("Offset must be non-negative") + recruiting = self.recruiting_repository.get_recruiting_by_id(recruiting_id) if recruiting is None: raise RecruitingNotFoundException()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@wacruit/src/apps/recruiting/services.py` around lines 283 - 292, The get_recruiting_submissions method is missing validation for limit/offset allowing negative or huge values; add checks at the start of get_recruiting_submissions to ensure offset >= 0, limit > 0 and limit <= RECRUITING_MAX_LIMIT (introduce a RECRUITING_MAX_LIMIT constant), coerce or reject non-int inputs, and raise a clear exception (e.g., ValueError or a domain-specific InvalidArgument) when validation fails before calling recruiting_repository.get_submissions_by_recruiting_id; include the parameter names (limit, offset) in the error message for easier debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@wacruit/src/apps/recruiting/repositories.py`:
- Around line 276-285: The subquery latest_code currently selects only
CodeSubmission.id, user_id, problem_id but not CodeSubmission.code, which causes
RecruitingSubmissionResponse (with problem_1_code/problem_2_code/problem_3_code)
to miss data; fix by adding CodeSubmission.code to the latest_code select and
ensure the final query (the projection that builds RecruitingSubmissionResponse)
selects/aliases the code values into the expected fields (e.g., map codes for
each problem to problem_1_code/problem_2_code/problem_3_code) so the row dict
passed to RecruitingSubmissionResponse(**row) contains those keys;
alternatively, if code is truly unnecessary, remove the problem_*_code fields
from the RecruitingSubmissionResponse schema instead.
- Around line 194-220: The code accesses question_ids[0..2] and
problem_ids[0..2] without validating lengths, risking IndexError; update the
block after fetching question_ids and problem_ids (the results of
self.session.execute(select(ResumeQuestion.id)...) and select(Problem.id)...) to
first check that len(question_ids) >= 3 and len(problem_ids) >= 3 and if not
raise a clear exception (e.g., ValueError including recruiting_id) or handle the
short-case appropriately, then safely assign q1_id,q2_id,q3_id and
p1_id,p2_id,p3_id (or use tuple unpacking after the length check) so the code
never indexes out of range.
- Around line 191-193: Add an explicit return type annotation to the method
get_submissions_by_recruiting_id to improve type checking and readability;
update its signature to include an appropriate return type such as
list[Submission] or Sequence[Submission] (or the project's ORM type e.g.,
QuerySet[Submission]) and import the needed typing symbol (List/Sequence) and
Submission model/type if not already imported, making sure the annotated type
matches the actual value returned by the method.
In `@wacruit/src/apps/recruiting/services.py`:
- Around line 283-292: get_recruiting_submissions currently returns an empty
list for unknown recruiting_id; add an existence check at the start by reusing
the existing validation logic (call self.get_recruiting_by_id(recruiting_id) or
use the repository existence/get method used by
get_recruiting_by_id/get_user_recruiting_by_id) and let it raise the same
NotFound/validation error when the recruiting doesn't exist, then proceed to
fetch submissions and build RecruitingSubmissionListResponse only if the
recruiting exists.
---
Nitpick comments:
In `@wacruit/src/apps/recruiting/repositories.py`:
- Around line 357-365: The final SELECT redundantly wraps code_pivot's
already-coalesced columns with func.coalesce again; remove the extra coalesce
calls in the projection and reference code_pivot.c.problem_1_correct,
code_pivot.c.problem_2_correct, code_pivot.c.problem_3_correct (etc.) directly
while preserving their .label("problem_X_correct") names so the
previously-applied coalesce in the code_pivot subquery remains the single source
of NULL->0 handling.
In `@wacruit/src/apps/recruiting/schemas.py`:
- Around line 16-17: Remove the empty TYPE_CHECKING block in
wacruit/src/apps/recruiting/schemas.py: locate the "if TYPE_CHECKING:" block and
delete it (including its pass) since there are no conditional type-only imports;
if you later need type-only imports retain TYPE_CHECKING and add the imports
inside the block.
In `@wacruit/src/apps/recruiting/services.py`:
- Around line 283-292: The get_recruiting_submissions method is missing
validation for limit/offset allowing negative or huge values; add checks at the
start of get_recruiting_submissions to ensure offset >= 0, limit > 0 and limit
<= RECRUITING_MAX_LIMIT (introduce a RECRUITING_MAX_LIMIT constant), coerce or
reject non-int inputs, and raise a clear exception (e.g., ValueError or a
domain-specific InvalidArgument) when validation fails before calling
recruiting_repository.get_submissions_by_recruiting_id; include the parameter
names (limit, offset) in the error message for easier debugging.
In `@wacruit/src/apps/recruiting/views_v3.py`:
- Around line 88-96: The get_recruiting_submission endpoint currently declares
limit and offset via Query without validation; update the parameter declarations
in get_recruiting_submission to add appropriate Query constraints (e.g., limit
with ge=1 and a sensible le like 1000, offset with ge=0) so FastAPI performs
early validation and documents these bounds; modify the Query(...) calls for the
limit and offset parameters used in the get_recruiting_submission function
signature to include these ge/le constraints.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c97e7385-4628-474d-9994-a65f573bde14
📒 Files selected for processing (4)
wacruit/src/apps/recruiting/repositories.pywacruit/src/apps/recruiting/schemas.pywacruit/src/apps/recruiting/services.pywacruit/src/apps/recruiting/views_v3.py
| def get_submissions_by_recruiting_id( | ||
| self, recruiting_id: int, limit: int, offset: int | ||
| ): |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
반환 타입 주석이 누락되었습니다.
메서드의 반환 타입을 명시하면 타입 체킹과 코드 가독성이 향상됩니다.
📝 제안하는 타입 주석 추가
- def get_submissions_by_recruiting_id(
- self, recruiting_id: int, limit: int, offset: int
- ):
+ def get_submissions_by_recruiting_id(
+ self, recruiting_id: int, limit: int, offset: int
+ ) -> Sequence[dict]:🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@wacruit/src/apps/recruiting/repositories.py` around lines 191 - 193, Add an
explicit return type annotation to the method get_submissions_by_recruiting_id
to improve type checking and readability; update its signature to include an
appropriate return type such as list[Submission] or Sequence[Submission] (or the
project's ORM type e.g., QuerySet[Submission]) and import the needed typing
symbol (List/Sequence) and Submission model/type if not already imported, making
sure the annotated type matches the actual value returned by the method.
| def get_recruiting_submissions( | ||
| self, recruiting_id: int, limit: int, offset: int | ||
| ) -> RecruitingSubmissionListResponse: | ||
| raw_submissions = self.recruiting_repository.get_submissions_by_recruiting_id( | ||
| recruiting_id, limit, offset | ||
| ) | ||
|
|
||
| parsed_items = [RecruitingSubmissionResponse(**row) for row in raw_submissions] | ||
|
|
||
| return RecruitingSubmissionListResponse(items=parsed_items) |
There was a problem hiding this comment.
recruiting_id 존재 여부 검증이 누락되었습니다.
다른 메서드들(get_recruiting_by_id, get_user_recruiting_by_id 등)과 달리 이 메서드는 recruiting_id의 유효성을 검증하지 않습니다. 존재하지 않는 recruiting_id로 호출해도 빈 리스트를 반환하여, 클라이언트가 "존재하지 않는 모집"과 "지원자가 없는 모집"을 구분할 수 없습니다.
🛡️ 제안하는 검증 추가
def get_recruiting_submissions(
self, recruiting_id: int, limit: int, offset: int
) -> RecruitingSubmissionListResponse:
+ recruiting = self.recruiting_repository.get_recruiting_by_id(recruiting_id)
+ if recruiting is None:
+ raise RecruitingNotFoundException()
+
raw_submissions = self.recruiting_repository.get_submissions_by_recruiting_id(
recruiting_id, limit, offset
)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@wacruit/src/apps/recruiting/services.py` around lines 283 - 292,
get_recruiting_submissions currently returns an empty list for unknown
recruiting_id; add an existence check at the start by reusing the existing
validation logic (call self.get_recruiting_by_id(recruiting_id) or use the
repository existence/get method used by
get_recruiting_by_id/get_user_recruiting_by_id) and let it raise the same
NotFound/validation error when the recruiting doesn't exist, then proceed to
fetch submissions and build RecruitingSubmissionListResponse only if the
recruiting exists.