Conversation
AiPinGenerationRateLimitService를 IssuePinDailyRateLimitService로 통합하고, uid/pin_id 기준 Redis 일일 제한(assert/record)과 GET quota 엔드포인트를 추가한다.
Feat/30 사용횟수 제한 기능 구현
There was a problem hiding this comment.
Code Review
This pull request introduces a daily rate limiting system for AI pin generation, issue pin creation, and issue pin editing using Redis. It adds the IssuePinDailyRateLimitService to manage daily quotas, exposes new endpoints to query quota status, and integrates rate limit checks into the core IssueService operations. Additionally, the PR includes comprehensive unit tests and updated documentation. The reviewer suggested refactoring ensure_issue_pin_edit_access in IssueService.py to return the validated issue_pin object, which would eliminate duplicate validation logic in other methods like update_issue_pin.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| async def ensure_issue_pin_edit_access(self, *, uid: str, pin_id: int) -> None: | ||
| issue_pin = await self._issue_pin_repo.get_by_pin_id(pin_id) | ||
| if issue_pin is None or issue_pin.pin is None: | ||
| raise_business_exception(ErrorCode.ISSUE_NOT_FOUND) | ||
|
|
||
| pin = issue_pin.pin | ||
| if pin.pin_type != PinType.ISSUE: | ||
| raise_business_exception(ErrorCode.ISSUE_NOT_FOUND) | ||
| if pin.uid != uid: | ||
| raise_business_exception(ErrorCode.FORBIDDEN) | ||
| if issue_pin.issue_pin_state != IssuePinState.BEFORE_PROGRESS: | ||
| raise_business_exception(ErrorCode.ISSUE_PIN_EDIT_VALIDATION) | ||
| if pin.pin_location is None: | ||
| raise_business_exception(ErrorCode.ISSUE_PIN_EDIT_FAILED) |
There was a problem hiding this comment.
ensure_issue_pin_edit_access 메서드가 검증된 issue_pin 객체를 반환하도록 수정하면, update_issue_pin 메서드 등에서 중복되는 검증 로직을 제거하고 코드를 더 깔끔하게 리팩토링할 수 있습니다.
현재 update_issue_pin 메서드 내에는 이 메서드와 완전히 동일한 검증 로직이 중복되어 존재하므로, 이 메서드가 IssuePin을 반환하도록 변경하여 중복을 줄이는 것을 권장합니다.
| async def ensure_issue_pin_edit_access(self, *, uid: str, pin_id: int) -> None: | |
| issue_pin = await self._issue_pin_repo.get_by_pin_id(pin_id) | |
| if issue_pin is None or issue_pin.pin is None: | |
| raise_business_exception(ErrorCode.ISSUE_NOT_FOUND) | |
| pin = issue_pin.pin | |
| if pin.pin_type != PinType.ISSUE: | |
| raise_business_exception(ErrorCode.ISSUE_NOT_FOUND) | |
| if pin.uid != uid: | |
| raise_business_exception(ErrorCode.FORBIDDEN) | |
| if issue_pin.issue_pin_state != IssuePinState.BEFORE_PROGRESS: | |
| raise_business_exception(ErrorCode.ISSUE_PIN_EDIT_VALIDATION) | |
| if pin.pin_location is None: | |
| raise_business_exception(ErrorCode.ISSUE_PIN_EDIT_FAILED) | |
| async def ensure_issue_pin_edit_access(self, *, uid: str, pin_id: int) -> IssuePin: | |
| issue_pin = await self._issue_pin_repo.get_by_pin_id(pin_id) | |
| if issue_pin is None or issue_pin.pin is None: | |
| raise_business_exception(ErrorCode.ISSUE_NOT_FOUND) | |
| pin = issue_pin.pin | |
| if pin.pin_type != PinType.ISSUE: | |
| raise_business_exception(ErrorCode.ISSUE_NOT_FOUND) | |
| if pin.uid != uid: | |
| raise_business_exception(ErrorCode.FORBIDDEN) | |
| if issue_pin.issue_pin_state != IssuePinState.BEFORE_PROGRESS: | |
| raise_business_exception(ErrorCode.ISSUE_PIN_EDIT_VALIDATION) | |
| if pin.pin_location is None: | |
| raise_business_exception(ErrorCode.ISSUE_PIN_EDIT_FAILED) | |
| return issue_pin |
✨ 작업 개요