-
Notifications
You must be signed in to change notification settings - Fork 1
[Feat] 회원가입 시 필수 약관 동의 추가 #171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package checkmo.member.internal.repository; | ||
|
|
||
| import checkmo.member.internal.entity.MemberTerms; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| public interface MemberTermsRepository extends JpaRepository<MemberTerms, Long> { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package checkmo.member.internal.repository; | ||
|
|
||
| import checkmo.member.internal.entity.Terms; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| public interface TermsRepository extends JpaRepository<Terms, Long> { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,12 +4,17 @@ | |||||||||||||||
| import checkmo.member.MemberEvent; | ||||||||||||||||
| import checkmo.member.internal.converter.MemberConverter; | ||||||||||||||||
| import checkmo.member.internal.entity.Member; | ||||||||||||||||
| import checkmo.member.internal.entity.MemberTerms; | ||||||||||||||||
| import checkmo.member.internal.entity.Terms; | ||||||||||||||||
| import checkmo.member.internal.exception.MemberErrorStatus; | ||||||||||||||||
| import checkmo.member.internal.exception.MemberException; | ||||||||||||||||
| import checkmo.member.internal.repository.MemberRepository; | ||||||||||||||||
| import checkmo.member.internal.repository.MemberTermsRepository; | ||||||||||||||||
| import checkmo.member.internal.repository.TermsRepository; | ||||||||||||||||
| import checkmo.member.web.dto.MemberRequestDTO; | ||||||||||||||||
| import checkmo.member.web.dto.MemberResponseDTO.DetailInfo; | ||||||||||||||||
| import java.util.HashSet; | ||||||||||||||||
| import java.util.List; | ||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||
| import org.springframework.context.ApplicationEventPublisher; | ||||||||||||||||
| import org.springframework.stereotype.Service; | ||||||||||||||||
|
|
@@ -26,7 +31,13 @@ public class MemberCommandService { | |||||||||||||||
|
|
||||||||||||||||
| private final ApplicationEventPublisher eventPublisher; | ||||||||||||||||
|
|
||||||||||||||||
| public void createMember(String memberId, String email) { | ||||||||||||||||
| private final MemberTermsRepository memberTermsRepository; | ||||||||||||||||
|
|
||||||||||||||||
| private final TermsRepository termsRepository; | ||||||||||||||||
|
|
||||||||||||||||
| public void createMember(String memberId, String email, List<Long> agreedTermsIds) { | ||||||||||||||||
| validateRequiredTerms(agreedTermsIds); | ||||||||||||||||
|
Comment on lines
+38
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider deduplicating If the caller passes - public void createMember(String memberId, String email, List<Long> agreedTermsIds) {
- validateRequiredTerms(agreedTermsIds);
+ public void createMember(String memberId, String email, List<Long> agreedTermsIds) {
+ List<Long> distinctTermsIds = agreedTermsIds != null
+ ? agreedTermsIds.stream().distinct().toList()
+ : null;
+ validateRequiredTerms(distinctTermsIds);Then use 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
|
|
||||||||||||||||
| Member member = Member.builder() | ||||||||||||||||
| .id(memberId) | ||||||||||||||||
| .email(email) | ||||||||||||||||
|
|
@@ -39,7 +50,30 @@ public void createMember(String memberId, String email) { | |||||||||||||||
|
|
||||||||||||||||
| memberRepository.save(member); | ||||||||||||||||
|
|
||||||||||||||||
| // TODO: 여기서 약관 내역 DB에 저장 (멤버 생성 후) | ||||||||||||||||
| // 여기서 약관 내역 DB에 저장 (멤버 생성 후) | ||||||||||||||||
| for (Long termsId : agreedTermsIds) { | ||||||||||||||||
| Terms terms = termsRepository.findById(termsId) | ||||||||||||||||
| .orElseThrow(() -> new MemberException(MemberErrorStatus.TERMS_NOT_FOUND)); | ||||||||||||||||
|
|
||||||||||||||||
| MemberTerms memberTerms = MemberTerms.builder() | ||||||||||||||||
| .member(member) | ||||||||||||||||
| .terms(terms) | ||||||||||||||||
| .isAgreed(true) | ||||||||||||||||
| .build(); | ||||||||||||||||
|
|
||||||||||||||||
| memberTermsRepository.save(memberTerms); | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+54
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 코드는 서비스 거부(DoS) 공격에 취약합니다. List<Terms> allTerms = termsRepository.findAllById(agreedTermsIds);
if (allTerms.size() != agreedTermsIds.size()) {
throw new MemberException(MemberErrorStatus.TERMS_NOT_FOUND);
}
List<MemberTerms> memberTermsToSave = allTerms.stream()
.map(term -> MemberTerms.builder()
.member(member)
.terms(term)
.isAgreed(true)
.build())
.collect(Collectors.toList());
memberTermsRepository.saveAll(memberTermsToSave); |
||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| private void validateRequiredTerms(List<Long> agreedTermsIds) { | ||||||||||||||||
| List<Long> requiredTermsIds = termsRepository.findAll().stream() | ||||||||||||||||
| .filter(Terms::isRequired) | ||||||||||||||||
| .map(Terms::getId) | ||||||||||||||||
| .toList(); | ||||||||||||||||
|
|
||||||||||||||||
| if (agreedTermsIds == null || !agreedTermsIds.containsAll(requiredTermsIds)) { | ||||||||||||||||
| throw new MemberException(MemberErrorStatus.REQUIRED_TERMS_NOT_AGREE); | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+69
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 필수 약관을 검증하는 로직이 비효율적입니다.
List<Long> requiredTermsIds = termsRepository.findAllByIsRequired(true).stream()
.map(Terms::getId)
.toList();
if (agreedTermsIds == null || !new HashSet<>(agreedTermsIds).containsAll(requiredTermsIds)) {
throw new MemberException(MemberErrorStatus.REQUIRED_TERMS_NOT_AGREE);
} |
||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
|
|
||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| INSERT INTO terms (id, term_url, is_required) VALUES | ||
| (1, 'https://www.notion.so/2cd7445c73f780dab5c5ccfbf5ce6101', true), -- 서비스 이용을 위한 필수 개인정보 수집 이용 동의(필수) | ||
| (2, 'https://www.notion.so/2cd7445c73f780e3a653ead96321331f', false), -- 마케팅 및 이벤트 정보 수신 동의 (선택) | ||
| (3, 'https://www.notion.so/3-2cd7445c73f7806f9b37f75eea6acb30', false); -- 개인정보 제3자 제공 동의(선택) | ||
|
Comment on lines
+1
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Find and check Terms entity for ID generation strategy
find . -type f -name "Terms.java" | head -5 | xargs -I {} sh -c 'echo "=== File: {} ===" && cat -n {}'Repository: checkmo2025/BE Length of output: 1048 🏁 Script executed: #!/bin/bash
# Find CREATE TABLE migration for terms
rg -n "CREATE TABLE" --type sql -A10 | grep -A10 "terms"Repository: checkmo2025/BE Length of output: 2687 🏁 Script executed: #!/bin/bash
# Check the exact last character(s) of the V20260211 file to confirm newline
hexdump -C src/main/resources/db/migration/V20260211__insert_default_terms.sql | tail -3Repository: checkmo2025/BE Length of output: 103 🏁 Script executed: #!/bin/bash
# Check trailing newline using od
tail -c 20 src/main/resources/db/migration/V20260211__insert_default_terms.sql | od -cRepository: checkmo2025/BE Length of output: 100 🏁 Script executed: #!/bin/bash
# Check if other seed data migrations also use explicit IDs
rg -n "INSERT INTO" --type sql -A1 src/main/resources/db/migration/ | head -40Repository: checkmo2025/BE Length of output: 966 🏁 Script executed: #!/bin/bash
# Check trailing newline using tail with -c and wc
file="src/main/resources/db/migration/V20260211__insert_default_terms.sql"
last_char=$(tail -c 1 "$file" | wc -l)
echo "Lines at end: $last_char"
# Also show last few characters using sed
echo "Last 5 chars:"
tail -c 5 "$file" | sed 's/.$/[END]/g' | cat -ARepository: checkmo2025/BE Length of output: 107 🏁 Script executed: #!/bin/bash
# Check all INSERT migrations to see if hardcoded IDs are the standard pattern
find src/main/resources/db/migration -name "*.sql" -type f -exec grep -l "INSERT INTO" {} \; | while read f; do
echo "=== $f ==="
grep -A2 "INSERT INTO" "$f" | head -6
doneRepository: checkmo2025/BE Length of output: 863 Add trailing newline to the file; reconsider hardcoded IDs if sequence management is a project concern. The file is missing a trailing newline (line 4 ends without one). Regarding the hardcoded IDs (1, 2, 3): The 🤖 Prompt for AI Agents |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
rg -n "CreateMember" --type java -C3Repository: checkmo2025/BE
Length of output: 3426
🏁 Script executed:
rg -n "memberCommandService.createMember|createMember\(" --type java -C5 src/main/java/checkmo/member/Repository: checkmo2025/BE
Length of output: 2314
🏁 Script executed:
rg -n "validateRequiredTerms" --type java -A10 src/main/java/checkmo/member/Repository: checkmo2025/BE
Length of output: 2758
Fix social login signup: supply
agreedTermsIdsinCustomOAuth2UserService.CreateMemberbuilder.Social login flow in
CustomOAuth2UserService(line 56) publishesCreateMemberwithoutagreedTermsIds, causing it to be null. The event listener then callsMemberCommandService.createMember(), which validates required terms at line 74:if (agreedTermsIds == null || !agreedTermsIds.containsAll(requiredTermsIds))throwsMemberException. This breaks the social login signup flow. Either supply the agreed terms list (if social login should require terms agreement) or an empty list (if social login should skip this validation).🤖 Prompt for AI Agents