[feature] 상시 모집 상태 추가 및 모집 정보 변경 시 반영되도록 변경#485
Conversation
|
""" Walkthrough이 변경 사항은 동아리 모집 상태를 계산하는 로직을 Changes
Sequence Diagram(s)sequenceDiagram
participant ClubProfileService
participant RecruitmentStateCalculator
participant Club
ClubProfileService->>RecruitmentStateCalculator: calculate(club, startDate, endDate)
RecruitmentStateCalculator->>Club: 모집 상태 업데이트
ClubProfileService->>Club: 저장
sequenceDiagram
participant RecruitmentStateChecker
participant RecruitmentStateCalculator
participant Club
RecruitmentStateChecker->>RecruitmentStateCalculator: calculate(club, startDate, endDate)
RecruitmentStateCalculator->>Club: 모집 상태 업데이트
RecruitmentStateChecker->>Club: 저장
Assessment against linked issues
Assessment against linked issues: Out-of-scope changes(해당 사항 없음) Possibly related PRs
Suggested labels
Suggested reviewers
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Test Results78 tests 78 ✅ 2s ⏱️ Results for commit 589d0b7. ♻️ This comment has been updated with latest results. |
|
잘못된 테스트 코드 수정하기 전에 브랜치를 따서 만든 거라 테스트는 실패합니다. 실패하는 부분은 변경된 코드와 상관없습니다. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
backend/src/main/java/moadong/club/util/RecruitmentStateCalculator.java (1)
13-37: 메서드 문서화 권장복잡한 비즈니스 로직을 포함하고 있으므로 Javadoc 주석을 추가하여 각 상태 변경 조건을 명확히 문서화하는 것을 권장합니다.
다음과 같은 Javadoc을 추가하는 것을 고려해보세요:
+ /** + * 클럽의 모집 기간을 기반으로 모집 상태를 계산하고 업데이트합니다. + * + * @param club 모집 상태를 업데이트할 클럽 + * @param recruitmentStartDate 모집 시작일 (null일 경우 CLOSED) + * @param recruitmentEndDate 모집 종료일 (null이거나 2999년일 경우 특별 처리) + */ public static void calculate(Club club, ZonedDateTime recruitmentStartDate, ZonedDateTime recruitmentEndDate) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
backend/src/main/java/moadong/club/entity/Club.java(2 hunks)backend/src/main/java/moadong/club/service/ClubProfileService.java(3 hunks)backend/src/main/java/moadong/club/service/RecruitmentStateChecker.java(2 hunks)backend/src/main/java/moadong/club/util/RecruitmentStateCalculator.java(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
backend/src/main/java/moadong/club/service/ClubProfileService.java (2)
backend/src/main/java/moadong/club/util/RecruitmentStateCalculator.java (1)
RecruitmentStateCalculator(10-38)backend/src/main/java/moadong/global/util/ObjectIdConverter.java (1)
ObjectIdConverter(7-17)
backend/src/main/java/moadong/club/service/RecruitmentStateChecker.java (1)
backend/src/main/java/moadong/club/util/RecruitmentStateCalculator.java (1)
RecruitmentStateCalculator(10-38)
🔇 Additional comments (12)
backend/src/main/java/moadong/club/entity/Club.java (2)
18-19: LGTM: 코드 스타일 개선import 문 정렬이 코드 가독성을 향상시킵니다.
71-71: LGTM: 포맷팅 개선생성자 파라미터 들여쓰기가 일관성 있게 개선되었습니다.
backend/src/main/java/moadong/club/service/ClubProfileService.java (3)
11-11: LGTM: 적절한 의존성 추가새로운 RecruitmentStateCalculator 유틸리티 클래스를 import하여 모집 상태 계산 로직을 중앙화하는 것은 좋은 접근입니다.
47-51: LGTM: 모집 상태 계산 로직 통합RecruitmentStateCalculator를 사용하여 모집 정보 업데이트 시 상태를 자동으로 계산하도록 개선되었습니다. 이는 일관성 있는 상태 관리를 보장합니다.
27-30: LGTM: 코드 포맷팅 개선메서드 파라미터 정렬 및 예외 처리 포맷팅이 일관성 있게 개선되었습니다.
Also applies to: 44-44, 58-58, 61-61, 68-68
backend/src/main/java/moadong/club/service/RecruitmentStateChecker.java (3)
8-8: LGTM: 유틸리티 클래스 도입RecruitmentStateCalculator 유틸리티 클래스를 도입하여 코드 중복을 제거하고 유지보수성을 향상시켰습니다.
12-13: LGTM: Import 정리시간 관련 import가 깔끔하게 정리되었습니다.
31-31: LGTM: 로직 중앙화복잡한 모집 상태 계산 로직을 RecruitmentStateCalculator로 위임하여 코드 중복을 제거하고 일관성을 보장합니다.
backend/src/main/java/moadong/club/util/RecruitmentStateCalculator.java (4)
11-11: LGTM: 상시 모집 상수 정의2999년을 상시 모집 연도로 정의한 것은 명확하고 이해하기 쉽습니다.
14-21: LGTM: 예외 상황 처리null 값 처리와 상시 모집 상태 처리가 적절히 구현되었습니다.
22-22: LGTM: 타임존 설정Asia/Seoul 타임존을 명시적으로 지정하여 정확한 시간 비교를 보장합니다.
32-36: LGTM: 모집 상태 로직OPEN 및 CLOSED 상태 결정 로직이 올바르게 구현되었습니다.
| if (now.isBefore(recruitmentStartDate)) { | ||
| long between = ChronoUnit.DAYS.between(recruitmentStartDate, now); | ||
| if (between <= 14) { | ||
| club.updateRecruitmentStatus(ClubRecruitmentStatus.UPCOMING); | ||
| } else { | ||
| club.updateRecruitmentStatus(ClubRecruitmentStatus.CLOSED); | ||
| } |
There was a problem hiding this comment.
UPCOMING 상태 계산 로직 오류 수정 필요
현재 로직에 오류가 있습니다. now.isBefore(recruitmentStartDate) 상황에서 ChronoUnit.DAYS.between(recruitmentStartDate, now)를 계산하면 음수가 반환되는데, between <= 14 조건이 항상 true가 됩니다.
다음과 같이 수정해야 합니다:
- long between = ChronoUnit.DAYS.between(recruitmentStartDate, now);
+ long between = ChronoUnit.DAYS.between(now, recruitmentStartDate);이렇게 하면 모집 시작까지 남은 일수를 올바르게 계산하여, 14일 이내일 때만 UPCOMING 상태로 설정됩니다.
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/util/RecruitmentStateCalculator.java
around lines 25 to 31, the calculation of days between recruitmentStartDate and
now is reversed causing negative values and incorrect UPCOMING status. Fix this
by swapping the arguments in ChronoUnit.DAYS.between to calculate days from now
to recruitmentStartDate, ensuring the difference is positive and the condition
correctly checks if the recruitment start is within 14 days.
[feature] cloudflare 이미지 저장 기능 구현
Due-IT
left a comment
There was a problem hiding this comment.
고생하셨습니다 프론트에게 변경내용을 잘 전달해야겠네요
fix: 잘못된 비밀번호 검증 로직과 잘못된 비밀번호 테스트 수정
이미지 저장소 cloudflare로 고정
- recruitmentStatus -> clubRecruitmentStatus
…om/Moadong/moadong into feature/#470-always-recruit-MOA-18
There was a problem hiding this comment.
Actionable comments posted: 5
🔭 Outside diff range comments (1)
backend/src/main/java/moadong/club/repository/ClubSearchRepository.java (1)
72-73:⚠️ Potential issue필터링 조건에서도 동일한 필드명을 사용해야 합니다.
projection에서
clubRecruitmentStatus로 변경했지만, 여기서는 여전히 이전 필드명recruitmentStatus를 사용하고 있습니다. 이로 인해 모집 상태 필터링이 제대로 작동하지 않을 수 있습니다.다음과 같이 수정하여 일관성을 맞춰주세요:
- criteriaList.add( - Criteria.where("recruitmentInformation.recruitmentStatus").is(recruitmentStatus)); + criteriaList.add( + Criteria.where("recruitmentInformation.clubRecruitmentStatus").is(recruitmentStatus));
🧹 Nitpick comments (1)
backend/src/main/java/moadong/media/controller/ClubImageController.java (1)
29-33: 필드 선언을 생성자 앞으로 이동하세요.Java 컨벤션에 따르면 필드는 생성자보다 먼저 선언되어야 합니다.
+private final ClubImageService clubImageService; + public ClubImageController(@Qualifier("cloudflare") ClubImageService clubImageService) { this.clubImageService = clubImageService; } - -private final ClubImageService clubImageService;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
backend/build.gradle(1 hunks)backend/src/main/java/moadong/club/repository/ClubSearchRepository.java(1 hunks)backend/src/main/java/moadong/global/exception/ErrorCode.java(1 hunks)backend/src/main/java/moadong/global/validator/PasswordValidator.java(1 hunks)backend/src/main/java/moadong/media/controller/ClubImageController.java(2 hunks)backend/src/main/java/moadong/media/service/CloudflareImageService.java(1 hunks)backend/src/main/java/moadong/media/service/GcsClubImageService.java(2 hunks)backend/src/main/java/moadong/media/service/GoogleDriveClubImageService.java(3 hunks)backend/src/main/java/moadong/media/util/ClubImageUtil.java(1 hunks)backend/src/main/java/moadong/media/util/S3Config.java(1 hunks)backend/src/test/java/moadong/media/service/GoogleDriveClubImageServiceFeedTest.java(2 hunks)backend/src/test/java/moadong/media/service/GoogleDriveClubImageServiceLogoTest.java(3 hunks)backend/src/test/java/moadong/unit/user/PasswordValidatorTest.java(1 hunks)backend/src/test/java/moadong/unit/user/UserRegisterTest.java(0 hunks)
💤 Files with no reviewable changes (1)
- backend/src/test/java/moadong/unit/user/UserRegisterTest.java
✅ Files skipped from review due to trivial changes (3)
- backend/src/test/java/moadong/media/service/GoogleDriveClubImageServiceFeedTest.java
- backend/src/main/java/moadong/global/exception/ErrorCode.java
- backend/src/main/java/moadong/media/util/S3Config.java
🧰 Additional context used
🧬 Code Graph Analysis (2)
backend/src/main/java/moadong/media/service/GcsClubImageService.java (1)
backend/src/main/java/moadong/media/util/ClubImageUtil.java (1)
ClubImageUtil(13-62)
backend/src/test/java/moadong/media/service/GoogleDriveClubImageServiceLogoTest.java (1)
backend/src/main/java/moadong/media/util/ClubImageUtil.java (1)
ClubImageUtil(13-62)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: test
🔇 Additional comments (18)
backend/src/main/java/moadong/global/validator/PasswordValidator.java (3)
10-11: 정규식 패턴이 올바르게 개선되었습니다.정규식을 상수로 분리한 것은 유지보수성을 높이는 좋은 변경입니다.
(?!.*\\s)추가로 공백 문자를 명시적으로 금지하고,\d대신[0-9]를 사용한 것도 명확성을 높입니다.
14-14: 매개변수 이름 변경이 일관성을 높입니다.
constraintValidatorContext에서context로 변경한 것이 코드 가독성을 개선합니다.
15-17: null/empty 체크 로직이 명확해졌습니다.null이나 빈 문자열에 대해 명시적으로
false를 반환하도록 변경한 것이 의도를 더욱 분명하게 합니다.backend/src/test/java/moadong/unit/user/PasswordValidatorTest.java (4)
11-13: 테스트 클래스 구조가 잘 설계되었습니다.
@UnitTest어노테이션 사용과 PasswordValidator 인스턴스 생성이 적절합니다.
15-19: 유효한 비밀번호 테스트가 적절합니다.UserFixture를 사용하여 유효한 비밀번호를 테스트하는 것이 일관성 있는 접근입니다.
21-39: 포괄적인 무효 비밀번호 테스트 케이스들입니다.매개변수화된 테스트로 다양한 무효 케이스들을 체계적으로 검증하고 있습니다:
- 길이 제한 (너무 짧음/김)
- 필수 문자 유형 누락 (숫자, 영문자)
- 허용되지 않은 특수문자 (
*,(),~등)- 공백 포함
- 다양한 조합 실패 케이스
테스트 커버리지가 정규식의 모든 조건을 잘 검증하고 있습니다.
29-29:Details
✅ Verification successful
허용되지 않은 특수문자 테스트 케이스를 확인해주세요.
정규식에서 허용하는 특수문자는
[!@#$%^]인데, 테스트 케이스에서*가 허용되지 않는다고 명시되어 있습니다. 이는 정확합니다.다음 스크립트로 정규식과 테스트 케이스의 일치성을 확인해보겠습니다:
🏁 Script executed:
#!/bin/bash # 설명: PasswordValidator의 정규식과 테스트 케이스들이 일치하는지 확인 # 정규식에서 허용하는 특수문자 확인 echo "정규식에서 허용하는 특수문자: [!@#\$%^]" # 테스트 케이스에서 허용되지 않는다고 명시한 특수문자들 확인 echo "테스트에서 허용되지 않는다고 명시한 특수문자들:" rg -A 1 "허용되지 않은 특수문자" backend/src/test/java/moadong/unit/user/PasswordValidatorTest.javaLength of output: 433
허용되지 않는 특수문자(
*) 테스트 일치 확인
테스트 케이스의*는 정규식([!@#$%^])에 포함되지 않아 올바르게 검증되고 있습니다.backend/src/main/java/moadong/media/service/GcsClubImageService.java (2)
3-3: 파일명 검증 로직 개선이 잘 반영되었습니다.기존의
containsKorean에서containsInvalidChars로 변경하여 퍼센트 인코딩, 한글, 공백 등을 포함한 더 포괄적인 파일명 검증이 가능해졌습니다.
143-145: 개선된 파일명 검증 로직이 적절히 적용되었습니다.
containsInvalidChars메서드를 사용하여 파일명에 유효하지 않은 문자가 포함된 경우 랜덤 문자열로 교체하는 로직이 올바르게 구현되었습니다.backend/build.gradle (1)
57-63:Details
❓ Verification inconclusive
새로운 의존성 추가를 확인해 주세요.
AWS S3 통합과 이미지 처리를 위한 의존성들이 추가되었습니다. 다음 사항을 확인해 주세요:
- AWS SDK BOM 2.25.8 버전이 최신 안정 버전인지 확인
- 새로 추가되는 CloudflareImageService와의 연관성 검토
- Thumbnailator 0.4.14 버전의 보안 취약점 여부 확인
AWS SDK와 Thumbnailator의 최신 버전과 보안 이슈를 확인하기 위해 다음을 검색해 주세요:
🌐 Web query:
AWS SDK for Java BOM 2.25.8 version latest security advisories💡 Result:
Based on the search results, I'll provide an overview of the AWS SDK for Java BOM version 2.25.8 and relevant security information.
The AWS SDK for Java is currently on version 2.x, which is a major rewrite of the 1.x codebase built on top of Java 8+ with several new features including support for non-blocking I/O and the ability to use different HTTP implementations at runtime[9]. The latest version appears to be around 2.31.32, released on April 29, 2025[6].
Regarding security advisories specifically for version 2.25.8, there is no direct mention of this exact version in the search results. However, the most recent security advisory mentioned is from July 15, 2022, which identified a "Partial Path Traversal in com.amazonaws:aws-java-sdk-s3" vulnerability (GHSA-c28r-hw5m-5gv3) with a "High" severity rating[2].
The AWS SDK for Java v2 has had several recent releases with various bugfixes and features. The most recent releases include:
Version 2.31.32 (April 29, 2025) which included:
- Fixed timestamp unmarshalling off-by-one errors
- Added LegacyMd5Plugin to perform MD5 checksums for operations that require checksum
- Updated endpoint and partition metadata[6]
Version 2.31.31 (April 28, 2025) which included:
- Addition of native h2 support for the bedrock runtime API
- Updates to various AWS services including Certificate Manager, CloudFront, and DynamoDB[6]
There was also a recent issue with S3Client.deleteObjects not working in version 2.30.0, related to changes in checksum handling. This issue particularly affected Minio implementations but has since been resolved[1].
To use the latest AWS SDK for Java in your project, you would need to declare it as a dependency in your project's
pom.xmlfile. The recommended approach is to use the BOM (Bill of Materials) to manage dependencies:<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.31.32</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>Then you can add specific modules without specifying their version:
<dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3</artifactId> </dependency> </dependencies>For optimal security, it would be advisable to upgrade to the latest AWS SDK for Java version rather than staying on 2.25.8, as the newer versions contain security fixes and improvements[5][6].
Citations:
- 1: https://github.com/aws/aws-sdk-java-v2
- 2: https://github.com/aws/aws-sdk-java/security/advisories
- 3: https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-whats-different.html
- 4: https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-transfer-manager.html
- 5: https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html
- 6: https://github.com/aws/aws-sdk-java-v2/releases
- 7: https://central.sonatype.com/artifact/software.amazon.awssdk/aws-sdk-java-pom/2.25.43
- 8: https://aws.amazon.com/sdk-for-java/
- 9: https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html
- 10: https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/java_s3_code_examples.html
🌐 Web query:
Thumbnailator 0.4.14 library security vulnerabilities💡 Result:
As of June 6, 2025, there are no known security vulnerabilities associated with Thumbnailator version 0.4.14. The Maven Repository lists a dependency vulnerability, CVE-2020-15250, but this pertains to a different component and does not affect Thumbnailator. (mvnrepository.com)
Additionally, the Sonatype OSS Index reports no vulnerabilities detected in Thumbnailator. (ossindex.sonatype.org)
It's important to note that Thumbnailator 0.4.14 was released on March 10, 2021. The latest version available is 0.4.20, released on June 27, 2023. (repo1.maven.org)
While no vulnerabilities have been identified in version 0.4.14, it's advisable to consider upgrading to the latest version to benefit from any improvements and security patches.
Citations:
- 1: https://mvnrepository.com/artifact/net.coobird/thumbnailator/0.4.14?utm_source=openai
- 2: https://ossindex.sonatype.org/component/pkg%3Amaven/net.coobird/thumbnailator?utm_source=openai
- 3: https://repo1.maven.org/maven2/net/coobird/thumbnailator/?utm_source=openai
AWS SDK 및 Thumbnailator 버전 검토 필요
다음 사항을 확인하고 필요 시 버전 업그레이드를 검토해 주세요:
- backend/build.gradle (57–63):
– AWS SDK BOM 2.25.8 → 최신 안정 버전은 2.31.32(2025-04-29)입니다. 보안 패치와 버그 픽스 적용을 위해 업그레이드를 권장합니다.- Thumbnailator 0.4.14:
– 알려진 보안 취약점은 없으나 최신 버전은 0.4.20(2023-06-27)이므로 업데이트 고려가 필요합니다.- CloudflareImageService와의 연관성:
– 실제 구현에서 해당 의존성을 사용하는지 코드베이스에서 직접 확인해 주세요.backend/src/main/java/moadong/media/service/GoogleDriveClubImageService.java (2)
3-3: 파일명 검증 로직 개선이 일관되게 적용되었습니다.다른 이미지 서비스와 동일하게
containsInvalidChars메서드를 사용하도록 변경되어 일관성이 유지되었습니다.
25-25: 서비스 qualifier 추가가 적절합니다.여러 ClubImageService 구현체를 구분하기 위한 "googleDrive" qualifier 추가가 적절합니다. 이는 새로 추가되는 CloudflareImageService와의 구분을 위한 것으로 보입니다.
backend/src/test/java/moadong/media/service/GoogleDriveClubImageServiceLogoTest.java (2)
4-4: 테스트에 필요한 import가 적절히 추가되었습니다.새로운 테스트 메서드를 위한 assertion 메서드들과 유틸리티 클래스 import가 올바르게 추가되었습니다.
Also applies to: 7-7, 23-24
132-150: 포괄적인 파일명 검증 테스트가 잘 구현되었습니다.
containsInvalidChars메서드에 대한 다양한 테스트 케이스가 포함되어 있어 좋습니다:
- 정상 파일명
- 한글 포함
- 퍼센트 인코딩 포함
- 공백 포함
- 복합 조건
테스트 커버리지가 충분하고 엣지 케이스들이 잘 다뤄지고 있습니다.
backend/src/main/java/moadong/media/controller/ClubImageController.java (1)
36-36: Swagger 설명 업데이트가 적절합니다.모든 엔드포인트의 설명이 일관되게 "cloudflare"를 명시하도록 업데이트되었습니다.
Also applies to: 44-44, 51-51, 57-57
backend/src/main/java/moadong/media/util/ClubImageUtil.java (2)
17-20: 파일명 검증 로직이 개선되었습니다.메서드명이 더 명확해졌고, 퍼센트 인코딩, 한글, 공백 문자를 모두 검증하도록 확장되었습니다.
15-15: 이미지 확장자 검증 로직이 잘 구현되었습니다.허용된 확장자 목록을 Set으로 관리하고, null 체크와 확장자 추출 로직이 적절합니다.
Also applies to: 22-28
backend/src/main/java/moadong/media/service/CloudflareImageService.java (1)
1-173: PR 목적과 제공된 파일이 일치하지 않습니다.PR 설명에는 "상시 모집 상태 추가" 및 "RecruitmentStateCalculator로 리팩토링"이 언급되어 있지만, 제공된 파일들은 모두 이미지 처리 관련 변경사항입니다. 올바른 파일을 검토하고 있는지 확인해 주세요.
Likely an incorrect or invalid review comment.
| Aggregation.project("name", "state", "category", "division") | ||
| .and("recruitmentInformation.introduction").as("introduction") | ||
| .and("recruitmentInformation.recruitmentStatus").as("recruitmentStatus") | ||
| .and("recruitmentInformation.clubRecruitmentStatus").as("recruitmentStatus") |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
필드명 변경에 따른 일관성 확인이 필요합니다.
projection에서 recruitmentInformation.clubRecruitmentStatus로 변경되었지만, 72-73번째 줄의 getMatchedCriteria 메서드에서는 여전히 recruitmentInformation.recruitmentStatus를 사용하고 있습니다. 이로 인해 필터링과 projection 간에 불일치가 발생할 수 있습니다.
다음 스크립트를 실행하여 전체 코드베이스에서 필드명 사용 현황을 확인해주세요:
🏁 Script executed:
#!/bin/bash
# Description: Check usage of recruitment status field names across the codebase
echo "=== Searching for old field name 'recruitmentStatus' ==="
rg -A 3 "recruitmentInformation\.recruitmentStatus"
echo "=== Searching for new field name 'clubRecruitmentStatus' ==="
rg -A 3 "recruitmentInformation\.clubRecruitmentStatus"
echo "=== Checking RecruitmentStateCalculator usage ==="
rg -A 5 "RecruitmentStateCalculator"Length of output: 4971
getMatchedCriteria 필드명 일관성 수정 필요
getMatchedCriteria 메서드(72~73행)에서 여전히 사용 중인 "recruitmentInformation.recruitmentStatus"를 프로젝션에서 사용 중인 새 필드명 "recruitmentInformation.clubRecruitmentStatus"로 변경해야 합니다. 그렇지 않으면 필터링이 의도한 컬럼에 적용되지 않습니다.
대상 위치:
- 파일:
backend/src/main/java/moadong/club/repository/ClubSearchRepository.java - 라인: 약 72행 (getMatchedCriteria 내부)
제안하는 변경(diff):
- criteriaList.add(Criteria.where("recruitmentInformation.recruitmentStatus").is(recruitmentStatus));
+ criteriaList.add(Criteria.where("recruitmentInformation.clubRecruitmentStatus").is(recruitmentStatus));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .and("recruitmentInformation.clubRecruitmentStatus").as("recruitmentStatus") | |
| // ── getMatchedCriteria 메서드 내부 ── | |
| private List<Criteria> getMatchedCriteria(RecruitmentStatus recruitmentStatus) { | |
| List<Criteria> criteriaList = new ArrayList<>(); | |
| // …기존 다른 필터 조건… | |
| - criteriaList.add(Criteria.where("recruitmentInformation.recruitmentStatus") | |
| - .is(recruitmentStatus)); | |
| + criteriaList.add(Criteria.where("recruitmentInformation.clubRecruitmentStatus") | |
| + .is(recruitmentStatus)); | |
| return criteriaList; | |
| } |
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/repository/ClubSearchRepository.java
around line 72, update the field name used in the getMatchedCriteria method from
"recruitmentInformation.recruitmentStatus" to
"recruitmentInformation.clubRecruitmentStatus" to maintain consistency with the
projection field name and ensure correct filtering behavior.
| if (containsInvalidChars(fileName)) { | ||
| fileName = RandomStringUtil.generateRandomString(10); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
파일명 검증 로직이 올바르게 개선되었습니다.
containsInvalidChars 메서드를 사용하여 더 포괄적인 파일명 검증을 수행하도록 변경되었습니다. 다만 파일 확장자가 누락되는 문제가 있습니다.
현재 로직에서는 유효하지 않은 문자가 포함된 경우 확장자 없이 랜덤 문자열만 생성합니다:
- if (containsInvalidChars(fileName)) {
- fileName = RandomStringUtil.generateRandomString(10);
- }
+ if (containsInvalidChars(fileName)) {
+ String extension = "";
+ if (fileName.contains(".")) {
+ extension = fileName.substring(fileName.lastIndexOf("."));
+ }
+ fileName = RandomStringUtil.generateRandomString(10) + extension;
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (containsInvalidChars(fileName)) { | |
| fileName = RandomStringUtil.generateRandomString(10); | |
| } | |
| if (containsInvalidChars(fileName)) { | |
| String extension = ""; | |
| if (fileName.contains(".")) { | |
| extension = fileName.substring(fileName.lastIndexOf(".")); | |
| } | |
| fileName = RandomStringUtil.generateRandomString(10) + extension; | |
| } |
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/media/service/GoogleDriveClubImageService.java
around lines 138 to 140, the file name validation correctly checks for invalid
characters but replaces the entire file name with a random string, causing the
file extension to be lost. Modify the logic to preserve the original file
extension by extracting it from the original file name and appending it to the
generated random string when invalid characters are found.
| public static MultipartFile resizeImage(MultipartFile file, long maxSizeBytes) throws IOException { | ||
| double quality = 0.9; | ||
| int maxDim = 2000; | ||
| byte[] result; | ||
|
|
||
| while (true) { | ||
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||
| Thumbnails.of(file.getInputStream()) | ||
| .size(maxDim, maxDim) | ||
| .outputQuality(quality) | ||
| .outputFormat("jpg") // 용량 줄이기 좋음 | ||
| .toOutputStream(baos); | ||
|
|
||
| result = baos.toByteArray(); | ||
|
|
||
| if (result.length <= maxSizeBytes || (quality <= 0.3 && maxDim <= 800)) { | ||
| break; | ||
| } | ||
| quality -= 0.1; | ||
| maxDim -= 200; | ||
| file = new MockMultipartFile(file.getName(), file.getOriginalFilename(), | ||
| file.getContentType(), new ByteArrayInputStream(file.getBytes())); | ||
| } | ||
|
|
||
| return new MockMultipartFile( | ||
| file.getName(), | ||
| file.getOriginalFilename(), | ||
| "image/jpeg", | ||
| new ByteArrayInputStream(result) | ||
| ); | ||
| } |
There was a problem hiding this comment.
이미지 리사이징 로직에 버그가 있습니다.
51번 줄에서 file.getBytes()를 사용하면 원본 파일의 바이트를 계속 읽어오므로, 리사이징된 이미지가 아닌 원본 이미지를 반복적으로 처리하게 됩니다.
- file = new MockMultipartFile(file.getName(), file.getOriginalFilename(),
- file.getContentType(), new ByteArrayInputStream(file.getBytes()));
+ file = new MockMultipartFile(file.getName(), file.getOriginalFilename(),
+ "image/jpeg", new ByteArrayInputStream(result));추가로, 무한 루프를 방지하기 위해 최대 반복 횟수를 설정하는 것을 고려해보세요.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public static MultipartFile resizeImage(MultipartFile file, long maxSizeBytes) throws IOException { | |
| double quality = 0.9; | |
| int maxDim = 2000; | |
| byte[] result; | |
| while (true) { | |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
| Thumbnails.of(file.getInputStream()) | |
| .size(maxDim, maxDim) | |
| .outputQuality(quality) | |
| .outputFormat("jpg") // 용량 줄이기 좋음 | |
| .toOutputStream(baos); | |
| result = baos.toByteArray(); | |
| if (result.length <= maxSizeBytes || (quality <= 0.3 && maxDim <= 800)) { | |
| break; | |
| } | |
| quality -= 0.1; | |
| maxDim -= 200; | |
| file = new MockMultipartFile(file.getName(), file.getOriginalFilename(), | |
| file.getContentType(), new ByteArrayInputStream(file.getBytes())); | |
| } | |
| return new MockMultipartFile( | |
| file.getName(), | |
| file.getOriginalFilename(), | |
| "image/jpeg", | |
| new ByteArrayInputStream(result) | |
| ); | |
| } | |
| public static MultipartFile resizeImage(MultipartFile file, long maxSizeBytes) throws IOException { | |
| double quality = 0.9; | |
| int maxDim = 2000; | |
| byte[] result; | |
| while (true) { | |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
| Thumbnails.of(file.getInputStream()) | |
| .size(maxDim, maxDim) | |
| .outputQuality(quality) | |
| .outputFormat("jpg") // 용량 줄이기 좋음 | |
| .toOutputStream(baos); | |
| result = baos.toByteArray(); | |
| if (result.length <= maxSizeBytes || (quality <= 0.3 && maxDim <= 800)) { | |
| break; | |
| } | |
| quality -= 0.1; | |
| maxDim -= 200; | |
| - file = new MockMultipartFile(file.getName(), file.getOriginalFilename(), | |
| - file.getContentType(), new ByteArrayInputStream(file.getBytes())); | |
| + file = new MockMultipartFile(file.getName(), file.getOriginalFilename(), | |
| + "image/jpeg", new ByteArrayInputStream(result)); | |
| } | |
| return new MockMultipartFile( | |
| file.getName(), | |
| file.getOriginalFilename(), | |
| "image/jpeg", | |
| new ByteArrayInputStream(result) | |
| ); | |
| } |
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/media/util/ClubImageUtil.java between lines 30
and 60, the resizeImage method incorrectly uses file.getBytes() inside the loop,
which always reads the original file bytes instead of the resized image bytes,
causing repeated processing of the original image. To fix this, update the file
variable with the resized image bytes stored in the result array instead of the
original file bytes. Additionally, add a maximum iteration count to the while
loop to prevent potential infinite looping when the image cannot be resized
below maxSizeBytes.
| if (containsInvalidChars(fileName)) { | ||
| fileName = RandomStringUtil.generateRandomString(10); | ||
| } |
There was a problem hiding this comment.
파일 확장자를 유지해야 합니다.
파일명에 유효하지 않은 문자가 있을 때 전체 파일명을 랜덤 문자열로 교체하면 확장자가 손실됩니다.
if (containsInvalidChars(fileName)) {
- fileName = RandomStringUtil.generateRandomString(10);
+ String extension = fileName.substring(fileName.lastIndexOf("."));
+ fileName = RandomStringUtil.generateRandomString(10) + extension;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (containsInvalidChars(fileName)) { | |
| fileName = RandomStringUtil.generateRandomString(10); | |
| } | |
| if (containsInvalidChars(fileName)) { | |
| String extension = fileName.substring(fileName.lastIndexOf(".")); | |
| fileName = RandomStringUtil.generateRandomString(10) + extension; | |
| } |
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/media/service/CloudflareImageService.java
around lines 134 to 136, when the fileName contains invalid characters, the
current code replaces the entire fileName with a random string, causing the file
extension to be lost. Modify the code to preserve the original file extension by
extracting it before generating the random string and then appending it to the
new random fileName.
| public void deleteFile(Club club, String filePath) { | ||
| // https://pub-8655aea549d544239ad12d0385aa98aa.r2.dev/{key} -> {key} | ||
| String key = filePath.substring(viewEndpoint.length()+1); | ||
|
|
||
| DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() | ||
| .bucket(bucketName) | ||
| .key(key) | ||
| .build(); | ||
|
|
||
| s3Client.deleteObject(deleteRequest); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
URL 파싱 로직을 개선하세요.
현재 substring을 사용한 방식은 URL 형식이 변경되면 오류가 발생할 수 있습니다. URL 파싱을 더 안전하게 처리하는 것이 좋습니다.
public void deleteFile(Club club, String filePath) {
- // https://pub-8655aea549d544239ad12d0385aa98aa.r2.dev/{key} -> {key}
- String key = filePath.substring(viewEndpoint.length()+1);
+ if (!filePath.startsWith(viewEndpoint)) {
+ throw new RestApiException(ErrorCode.INVALID_FILE_PATH);
+ }
+ String key = filePath.substring(viewEndpoint.length())
+ .replaceFirst("^/", ""); // 선행 슬래시 제거📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public void deleteFile(Club club, String filePath) { | |
| // https://pub-8655aea549d544239ad12d0385aa98aa.r2.dev/{key} -> {key} | |
| String key = filePath.substring(viewEndpoint.length()+1); | |
| DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() | |
| .bucket(bucketName) | |
| .key(key) | |
| .build(); | |
| s3Client.deleteObject(deleteRequest); | |
| } | |
| public void deleteFile(Club club, String filePath) { | |
| if (!filePath.startsWith(viewEndpoint)) { | |
| throw new RestApiException(ErrorCode.INVALID_FILE_PATH); | |
| } | |
| String key = filePath.substring(viewEndpoint.length()) | |
| .replaceFirst("^/", ""); // 선행 슬래시 제거 | |
| DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() | |
| .bucket(bucketName) | |
| .key(key) | |
| .build(); | |
| s3Client.deleteObject(deleteRequest); | |
| } |
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/media/service/CloudflareImageService.java
around lines 111 to 121, the current method uses substring to extract the key
from the filePath URL, which is fragile if the URL format changes. Replace this
with a more robust URL parsing approach, such as using Java's URI or URL classes
to parse the filePath and safely extract the path component after the
viewEndpoint, ensuring the key is correctly obtained regardless of URL format
variations.
#️⃣연관된 이슈
#470
📝작업 내용
=> 유틸 클래스로 만들어서 다른 서비스에서도 사용할 수 있도록 변경
모집 정보 수정 요청

모집 정보 수정 결과

중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
Summary by CodeRabbit
New Features
Refactor
Tests