-
Notifications
You must be signed in to change notification settings - Fork 1
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
feat: 스터디 수료 및 철회 API 구현 #819
Changes from 3 commits
b639438
b21ce3e
f9dc1c3
acbcfdf
7473388
f5865f2
269c766
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,39 @@ | ||
package com.gdschongik.gdsc.domain.study.api; | ||
|
||
import com.gdschongik.gdsc.domain.study.application.MentorStudyHistoryService; | ||
import com.gdschongik.gdsc.domain.study.dto.request.StudyCompletionRequest; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PatchMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@Tag(name = "Mentor Study History", description = "멘토 스터디 수강 이력 API입니다.") | ||
@RestController | ||
@RequestMapping("/mentor/study-history") | ||
@RequiredArgsConstructor | ||
public class MentorStudyHistoryController { | ||
|
||
private final MentorStudyHistoryService mentorStudyHistoryService; | ||
|
||
@Operation(summary = "스터디 수료 처리", description = "스터디 수료 처리합니다.") | ||
@PatchMapping("/complete") | ||
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. patch보다는 post가 적절할 것 같습니다. |
||
public ResponseEntity<Void> completeStudy( | ||
@RequestParam(name = "studyId") Long studyId, @Valid @RequestBody StudyCompletionRequest request) { | ||
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. request dto 안에 studyId를 넣는게 좋을 것 같네요 |
||
mentorStudyHistoryService.completeStudy(studyId, request); | ||
return ResponseEntity.ok().build(); | ||
} | ||
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. 🛠️ Refactor suggestion 응답 처리와 검증 로직 개선이 필요합니다. 현재 구현에서 몇 가지 개선 포인트가 있습니다:
다음과 같은 개선을 제안드립니다: -public ResponseEntity<Void> completeStudy(
+public ResponseEntity<ApiResponse> completeStudy(
@RequestParam(name = "studyId") Long studyId,
@Valid @RequestBody StudyCompletionRequest request) {
mentorStudyHistoryService.completeStudy(studyId, request);
- return ResponseEntity.ok().build();
+ return ResponseEntity.ok(new ApiResponse("스터디 수료 처리가 완료되었습니다."));
} 또한 다음 사항도 고려해보시기 바랍니다:
|
||
|
||
@Operation(summary = "스터디 수료 철회", description = "스터디 수료 처리를 철회합니다.") | ||
@PatchMapping("/withdraw-completion") | ||
public ResponseEntity<Void> withdrawStudyCompletion( | ||
@RequestParam(name = "studyId") Long studyId, @Valid @RequestBody StudyCompletionRequest request) { | ||
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. DTO에 제약 조건이 없는데 혹시 @Valid 어노테이션이 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. 복붙이 이렇게 무섭습니다,, |
||
mentorStudyHistoryService.withdrawStudyCompletion(studyId, request); | ||
return ResponseEntity.ok().build(); | ||
} | ||
Sangwook02 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package com.gdschongik.gdsc.domain.study.application; | ||
|
||
import static com.gdschongik.gdsc.global.exception.ErrorCode.*; | ||
|
||
import com.gdschongik.gdsc.domain.member.domain.Member; | ||
import com.gdschongik.gdsc.domain.study.dao.StudyHistoryRepository; | ||
import com.gdschongik.gdsc.domain.study.dao.StudyRepository; | ||
import com.gdschongik.gdsc.domain.study.domain.Study; | ||
import com.gdschongik.gdsc.domain.study.domain.StudyHistory; | ||
import com.gdschongik.gdsc.domain.study.domain.StudyHistoryValidator; | ||
import com.gdschongik.gdsc.domain.study.domain.StudyValidator; | ||
import com.gdschongik.gdsc.domain.study.dto.request.StudyCompletionRequest; | ||
import com.gdschongik.gdsc.global.exception.CustomException; | ||
import com.gdschongik.gdsc.global.util.MemberUtil; | ||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class MentorStudyHistoryService { | ||
|
||
private final MemberUtil memberUtil; | ||
private final StudyValidator studyValidator; | ||
private final StudyHistoryValidator studyHistoryValidator; | ||
private final StudyRepository studyRepository; | ||
private final StudyHistoryRepository studyHistoryRepository; | ||
|
||
@Transactional | ||
public void completeStudy(Long studyId, StudyCompletionRequest request) { | ||
Member currentMember = memberUtil.getCurrentMember(); | ||
Study study = studyRepository.findById(studyId).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND)); | ||
List<StudyHistory> studyHistories = studyHistoryRepository.findAllById(request.studentIds()); | ||
|
||
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. StudyHistory의 Study 일치 여부 검증 필요 현재 수정 제안: List<StudyHistory> studyHistories = studyHistoryRepository.findAllById(request.studentIds());
+studyHistories = studyHistories.stream()
+ .filter(history -> history.getStudy().getId().equals(studyId))
+ .collect(Collectors.toList()); 또는
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. 굿 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. @Sangwook02, 수정 사항을 반영해 주셔서 감사합니다! If you found this review helpful, would you consider giving us a shout-out on X? |
||
studyValidator.validateStudyMentor(currentMember, study); | ||
studyHistoryValidator.validateAppliedToStudy( | ||
studyHistories.size(), request.studentIds().size()); | ||
|
||
studyHistories.forEach(StudyHistory::complete); | ||
|
||
log.info("[MentorStudyHistoryService] 스터디 수료 처리: studyId={}, studentIds={}", studyId, request.studentIds()); | ||
} | ||
|
||
@Transactional | ||
public void withdrawStudyCompletion(Long studyId, StudyCompletionRequest request) { | ||
Member currentMember = memberUtil.getCurrentMember(); | ||
Study study = studyRepository.findById(studyId).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND)); | ||
List<StudyHistory> studyHistories = studyHistoryRepository.findAllById(request.studentIds()); | ||
|
||
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. StudyHistory의 Study 일치 여부 검증 필요
수정 제안: List<StudyHistory> studyHistories = studyHistoryRepository.findAllById(request.studentIds());
+studyHistories = studyHistories.stream()
+ .filter(history -> history.getStudy().getId().equals(studyId))
+ .collect(Collectors.toList()); 또는
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. 굿 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. @Sangwook02, 감사합니다! |
||
studyValidator.validateStudyMentor(currentMember, study); | ||
studyHistoryValidator.validateAppliedToStudy( | ||
studyHistories.size(), request.studentIds().size()); | ||
|
||
studyHistories.forEach(StudyHistory::withdrawCompletion); | ||
|
||
log.info("[MentorStudyHistoryService] 스터디 수료 철회: studyId={}, studentIds={}", studyId, request.studentIds()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,6 +78,13 @@ public void complete() { | |
studyHistoryStatus = COMPLETED; | ||
} | ||
|
||
/** | ||
* 스터디 수료 철회 | ||
*/ | ||
public void withdrawCompletion() { | ||
studyHistoryStatus = NONE; | ||
} | ||
Comment on lines
+81
to
+86
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. 🛠️ Refactor suggestion 문서화 개선 및 상태 검증 로직 추가 필요 현재 구현은 기본적인 기능은 제공하지만, 다음 사항들을 고려해 주시기 바랍니다:
다음과 같은 개선을 제안드립니다: /**
* 스터디 수료 철회
+ *
+ * @throws IllegalStateException 현재 상태가 COMPLETED가 아닌 경우
*/
public void withdrawCompletion() {
+ if (studyHistoryStatus != COMPLETED) {
+ throw new IllegalStateException("수료 상태인 경우에만 철회가 가능합니다.");
+ }
studyHistoryStatus = NONE;
+ registerEvent(new StudyCompletionWithdrawnEvent(this.study.getId(), this.student.getId()));
}
|
||
|
||
// 데이터 전달 로직 | ||
public boolean isWithinApplicationAndCourse() { | ||
return study.isWithinApplicationAndCourse(); | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,5 @@ | ||||||
package com.gdschongik.gdsc.domain.study.dto.request; | ||||||
|
||||||
import java.util.List; | ||||||
|
||||||
public record StudyCompletionRequest(List<Long> studentIds) {} | ||||||
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.
Suggested change
|
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.
보안 및 권한 검증이 필요합니다.
컨트롤러 레벨에서 다음 보안 관련 개선사항이 필요합니다:
@PreAuthorize("hasRole('MENTOR')")
어노테이션 추가@Tag(name = "Mentor Study History", description = "멘토 스터디 수강 이력 API입니다.") +@PreAuthorize("hasRole('MENTOR')") @RestController @RequestMapping("/mentor/study-history") @RequiredArgsConstructor public class MentorStudyHistoryController {
📝 Committable suggestion