From 27409b01a05f4236c47ba58e6ddc306469327bf3 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 1 Aug 2024 10:44:36 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=ED=9C=B4=EA=B0=95=20=EC=B2=98=EB=A6=AC=20api=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/api/StudyMentorController.java | 10 +++++ .../study/application/StudyMentorService.java | 31 ++++++++++++++ .../gdsc/domain/study/domain/StudyDetail.java | 4 ++ .../domain/study/domain/vo/Assignment.java | 8 +++- .../gdsc/global/exception/ErrorCode.java | 3 ++ .../application/StudyMentorServiceTest.java | 40 +++++++++++++++++++ .../domain/study/domain/StudyDetailTest.java | 38 ++++++++++++++++++ .../global/common/constant/StudyConstant.java | 3 ++ .../gdschongik/gdsc/helper/FixtureHelper.java | 8 ++++ .../gdsc/helper/IntegrationTest.java | 40 +++++++++++++++++++ 10 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java create mode 100644 src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java create mode 100644 src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailTest.java diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyMentorController.java b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyMentorController.java index 5e6f2a344..9a46bb5ce 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyMentorController.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyMentorController.java @@ -1,5 +1,6 @@ package com.gdschongik.gdsc.domain.study.api; +import com.gdschongik.gdsc.domain.study.application.StudyMentorService; import com.gdschongik.gdsc.domain.study.domain.request.AssignmentCreateRequest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -14,10 +15,19 @@ @RequiredArgsConstructor public class StudyMentorController { + private final StudyMentorService studyMentorService; + @Operation(summary = "스터디 과제 개설", description = "멘토만 과제를 개설할 수 있습니다.") @PutMapping("/assignment/{assignmentId}") public ResponseEntity createStudyAssignment( @PathVariable Long assignmentId, @Valid @RequestBody AssignmentCreateRequest request) { return null; } + + @Operation(summary = "스터디 과제 휴강 처리", description = "해당 주차 과제를 휴강 처리합니다.") + @PatchMapping("/assignment/{studyDetailId}/cancel") + public ResponseEntity cancelStudyAssignment(@PathVariable Long studyDetailId) { + studyMentorService.cancelStudyAssignment(studyDetailId); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java new file mode 100644 index 000000000..b0d350c08 --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java @@ -0,0 +1,31 @@ +package com.gdschongik.gdsc.domain.study.application; + +import static com.gdschongik.gdsc.global.exception.ErrorCode.*; + +import com.gdschongik.gdsc.domain.study.dao.StudyDetailRepository; +import com.gdschongik.gdsc.domain.study.domain.StudyDetail; +import com.gdschongik.gdsc.global.exception.CustomException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class StudyMentorService { + + private final StudyDetailRepository studyDetailRepository; + + @Transactional + public void cancelStudyAssignment(Long studyDetailId) { + StudyDetail studyDetail = studyDetailRepository + .findById(studyDetailId) + .orElseThrow(() -> new CustomException(ASSIGNMENT_NOT_FOUND)); + + studyDetail.cancelAssignment(); + + log.info("[StudyMentorService] 과제 휴강 처리: studyDetailId={}", studyDetail.getId()); + } +} diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetail.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetail.java index 154ce8a90..bf76a233b 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetail.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetail.java @@ -69,4 +69,8 @@ public static StudyDetail createStudyDetail(Study study, Long week, String atten .assignment(Assignment.createEmptyAssignment()) .build(); } + + public void cancelAssignment() { + assignment = Assignment.cancelAssignment(); + } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/vo/Assignment.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/vo/Assignment.java index c426f35d6..9228bd4c0 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/vo/Assignment.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/vo/Assignment.java @@ -1,5 +1,7 @@ package com.gdschongik.gdsc.domain.study.domain.vo; +import static com.gdschongik.gdsc.domain.study.domain.StudyStatus.*; + import com.gdschongik.gdsc.domain.study.domain.Difficulty; import com.gdschongik.gdsc.domain.study.domain.StudyStatus; import jakarta.persistence.Column; @@ -46,6 +48,10 @@ private Assignment( } public static Assignment createEmptyAssignment() { - return Assignment.builder().status(StudyStatus.NONE).build(); + return Assignment.builder().status(NONE).build(); + } + + public static Assignment cancelAssignment() { + return Assignment.builder().status(CANCELLED).build(); } } diff --git a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java index 843ecbbcb..1ea3176a7 100644 --- a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java +++ b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java @@ -135,6 +135,9 @@ public enum ErrorCode { // Order - MoneyInfo ORDER_FINAL_PAYMENT_AMOUNT_MISMATCH(HttpStatus.CONFLICT, "주문 최종결제금액은 주문총액에서 할인금액을 뺀 값이어야 합니다."), + + // Assignment + ASSIGNMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "과제가 존재하지 않습니다."), ; private final HttpStatus status; diff --git a/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java b/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java new file mode 100644 index 000000000..1cd4285b8 --- /dev/null +++ b/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java @@ -0,0 +1,40 @@ +package com.gdschongik.gdsc.domain.study.application; + +import static org.assertj.core.api.Assertions.*; + +import com.gdschongik.gdsc.domain.study.dao.StudyDetailRepository; +import com.gdschongik.gdsc.domain.study.domain.StudyDetail; +import com.gdschongik.gdsc.domain.study.domain.StudyStatus; +import com.gdschongik.gdsc.helper.IntegrationTest; +import java.time.LocalDateTime; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class StudyMentorServiceTest extends IntegrationTest { + + @Autowired + private StudyMentorService studyMentorService; + + @Autowired + private StudyDetailRepository studyDetailRepository; + + @Nested + class 스터디_과제_휴강_처리시 { + + @Test + void 성공한다() { + // given + LocalDateTime now = LocalDateTime.now(); + StudyDetail studyDetail = createStudyDetail(now, now.plusDays(7)); + + // when + studyMentorService.cancelStudyAssignment(studyDetail.getId()); + + // then + StudyDetail cancelledStudyDetail = + studyDetailRepository.findById(studyDetail.getId()).get(); + assertThat(cancelledStudyDetail.getAssignment().getStatus()).isEqualTo(StudyStatus.CANCELLED); + } + } +} diff --git a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailTest.java b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailTest.java new file mode 100644 index 000000000..8118f4a1f --- /dev/null +++ b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailTest.java @@ -0,0 +1,38 @@ +package com.gdschongik.gdsc.domain.study.domain; + +import static org.assertj.core.api.Assertions.*; + +import com.gdschongik.gdsc.domain.member.domain.Member; +import com.gdschongik.gdsc.domain.recruitment.domain.vo.Period; +import com.gdschongik.gdsc.helper.FixtureHelper; +import java.time.LocalDateTime; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class StudyDetailTest { + + @Nested + class 과제_휴강_처리시 { + + FixtureHelper fixtureHelper = new FixtureHelper(); + + @Test + void 과제_상태가_휴강이_된다() { + // given + Member mentor = fixtureHelper.createAssociateMember(1L); + LocalDateTime now = LocalDateTime.now(); + StudyDetail studyDetail = fixtureHelper.createStudyDetail( + mentor, + Period.createPeriod(now.plusDays(5), now.plusDays(10)), + Period.createPeriod(now.minusDays(5), now), + now, + now.plusDays(7)); + + // when + studyDetail.cancelAssignment(); + + // then + assertThat(studyDetail.getAssignment().getStatus()).isEqualTo(StudyStatus.CANCELLED); + } + } +} diff --git a/src/test/java/com/gdschongik/gdsc/global/common/constant/StudyConstant.java b/src/test/java/com/gdschongik/gdsc/global/common/constant/StudyConstant.java index e263e49b8..0cc120400 100644 --- a/src/test/java/com/gdschongik/gdsc/global/common/constant/StudyConstant.java +++ b/src/test/java/com/gdschongik/gdsc/global/common/constant/StudyConstant.java @@ -13,4 +13,7 @@ private StudyConstant() {} public static final DayOfWeek DAY_OF_WEEK = DayOfWeek.FRIDAY; public static final LocalTime STUDY_START_TIME = LocalTime.of(19, 0, 0); public static final LocalTime STUDY_END_TIME = LocalTime.of(20, 0, 0); + + // StudyDetail + public static final String ATTENDANCE_NUMBER = "1234"; } diff --git a/src/test/java/com/gdschongik/gdsc/helper/FixtureHelper.java b/src/test/java/com/gdschongik/gdsc/helper/FixtureHelper.java index b0849699c..379da313c 100644 --- a/src/test/java/com/gdschongik/gdsc/helper/FixtureHelper.java +++ b/src/test/java/com/gdschongik/gdsc/helper/FixtureHelper.java @@ -18,6 +18,7 @@ import com.gdschongik.gdsc.domain.recruitment.domain.RoundType; import com.gdschongik.gdsc.domain.recruitment.domain.vo.Period; import com.gdschongik.gdsc.domain.study.domain.Study; +import com.gdschongik.gdsc.domain.study.domain.StudyDetail; import java.time.LocalDateTime; import org.springframework.test.util.ReflectionTestUtils; @@ -79,4 +80,11 @@ public Study createStudy(Member mentor, Period period, Period applicationPeriod) STUDY_START_TIME, STUDY_END_TIME); } + + public StudyDetail createStudyDetail( + Member mentor, Period period, Period applicationPeriod, LocalDateTime startDate, LocalDateTime endDate) { + Study study = createStudy(mentor, period, applicationPeriod); + + return StudyDetail.createStudyDetail(study, 1L, ATTENDANCE_NUMBER, Period.createPeriod(startDate, endDate)); + } } diff --git a/src/test/java/com/gdschongik/gdsc/helper/IntegrationTest.java b/src/test/java/com/gdschongik/gdsc/helper/IntegrationTest.java index 5a132ee69..4053200d5 100644 --- a/src/test/java/com/gdschongik/gdsc/helper/IntegrationTest.java +++ b/src/test/java/com/gdschongik/gdsc/helper/IntegrationTest.java @@ -4,6 +4,7 @@ import static com.gdschongik.gdsc.global.common.constant.MemberConstant.*; import static com.gdschongik.gdsc.global.common.constant.RecruitmentConstant.*; import static com.gdschongik.gdsc.global.common.constant.SemesterConstant.*; +import static com.gdschongik.gdsc.global.common.constant.StudyConstant.*; import static org.mockito.Mockito.*; import com.gdschongik.gdsc.domain.common.model.SemesterType; @@ -25,6 +26,10 @@ import com.gdschongik.gdsc.domain.recruitment.domain.RecruitmentRound; import com.gdschongik.gdsc.domain.recruitment.domain.RoundType; import com.gdschongik.gdsc.domain.recruitment.domain.vo.Period; +import com.gdschongik.gdsc.domain.study.dao.StudyDetailRepository; +import com.gdschongik.gdsc.domain.study.dao.StudyRepository; +import com.gdschongik.gdsc.domain.study.domain.Study; +import com.gdschongik.gdsc.domain.study.domain.StudyDetail; import com.gdschongik.gdsc.global.security.PrincipalDetails; import com.gdschongik.gdsc.infra.feign.payment.client.PaymentClient; import java.time.LocalDateTime; @@ -62,6 +67,12 @@ public abstract class IntegrationTest { @Autowired protected RecruitmentRoundRepository recruitmentRoundRepository; + @Autowired + protected StudyRepository studyRepository; + + @Autowired + protected StudyDetailRepository studyDetailRepository; + @MockBean protected OnboardingRecruitmentService onboardingRecruitmentService; @@ -160,4 +171,33 @@ protected IssuedCoupon createAndIssue(Money money, Member member) { IssuedCoupon issuedCoupon = IssuedCoupon.issue(coupon, member); return issuedCouponRepository.save(issuedCoupon); } + + protected Study createStudy(Member mentor, Period period, Period applicationPeriod) { + Study study = Study.createStudy( + ACADEMIC_YEAR, + SEMESTER_TYPE, + mentor, + period, + applicationPeriod, + TOTAL_WEEK, + ONLINE_STUDY, + DAY_OF_WEEK, + STUDY_START_TIME, + STUDY_END_TIME); + + return studyRepository.save(study); + } + + protected StudyDetail createStudyDetail(LocalDateTime startDate, LocalDateTime endDate) { + Member mentor = createAssociateMember(); + LocalDateTime now = LocalDateTime.now(); + Study study = createStudy( + mentor, + Period.createPeriod(now.plusDays(5), now.plusDays(10)), + Period.createPeriod(now.minusDays(5), now)); + + StudyDetail studyDetail = + StudyDetail.createStudyDetail(study, 1L, ATTENDANCE_NUMBER, Period.createPeriod(startDate, endDate)); + return studyDetailRepository.save(studyDetail); + } } From d75d76e2792a65c264c224d450b54d869afe1d3b Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 1 Aug 2024 11:35:39 +0900 Subject: [PATCH 02/10] =?UTF-8?q?fix:=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdsc/domain/study/api/StudyMentorController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyMentorController.java b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyMentorController.java index 9a46bb5ce..c6b9afa3c 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyMentorController.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyMentorController.java @@ -18,14 +18,14 @@ public class StudyMentorController { private final StudyMentorService studyMentorService; @Operation(summary = "스터디 과제 개설", description = "멘토만 과제를 개설할 수 있습니다.") - @PutMapping("/assignment/{assignmentId}") + @PutMapping("/assignments/{assignmentId}") public ResponseEntity createStudyAssignment( @PathVariable Long assignmentId, @Valid @RequestBody AssignmentCreateRequest request) { return null; } @Operation(summary = "스터디 과제 휴강 처리", description = "해당 주차 과제를 휴강 처리합니다.") - @PatchMapping("/assignment/{studyDetailId}/cancel") + @PatchMapping("/assignments/{studyDetailId}/cancel") public ResponseEntity cancelStudyAssignment(@PathVariable Long studyDetailId) { studyMentorService.cancelStudyAssignment(studyDetailId); return ResponseEntity.noContent().build(); From c85fc4c95230a642a31baf52da1ada4a9fafd9a0 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 1 Aug 2024 11:37:15 +0900 Subject: [PATCH 03/10] =?UTF-8?q?fix:=20=EC=97=90=EB=9F=AC=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdsc/domain/study/application/StudyMentorService.java | 2 +- .../com/gdschongik/gdsc/global/exception/ErrorCode.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java index b0d350c08..af2d57165 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java @@ -22,7 +22,7 @@ public class StudyMentorService { public void cancelStudyAssignment(Long studyDetailId) { StudyDetail studyDetail = studyDetailRepository .findById(studyDetailId) - .orElseThrow(() -> new CustomException(ASSIGNMENT_NOT_FOUND)); + .orElseThrow(() -> new CustomException(STUDY_DETAIL_NOT_FOUND)); studyDetail.cancelAssignment(); diff --git a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java index 1ea3176a7..d91f181d2 100644 --- a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java +++ b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java @@ -109,6 +109,9 @@ public enum ErrorCode { STUDY_NOT_APPLICABLE(HttpStatus.CONFLICT, "스터디 신청기간이 아닙니다."), STUDY_NOT_CANCELABLE_APPLICATION_PERIOD(HttpStatus.CONFLICT, "스터디 신청기간이 아니라면 취소할 수 없습니다."), + // StudyDetail + STUDY_DETAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 상세정보입니다."), + // StudyHistory STUDY_HISTORY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 수강 기록입니다."), STUDY_HISTORY_DUPLICATE(HttpStatus.CONFLICT, "이미 해당 스터디를 신청했습니다."), @@ -135,9 +138,6 @@ public enum ErrorCode { // Order - MoneyInfo ORDER_FINAL_PAYMENT_AMOUNT_MISMATCH(HttpStatus.CONFLICT, "주문 최종결제금액은 주문총액에서 할인금액을 뺀 값이어야 합니다."), - - // Assignment - ASSIGNMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "과제가 존재하지 않습니다."), ; private final HttpStatus status; From d5538eaf06c31b4d412c462849e5efa8c19a3712 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 2 Aug 2024 19:38:39 +0900 Subject: [PATCH 04/10] =?UTF-8?q?refactor:=20study=EB=A5=BC=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=EC=97=90=EC=84=9C=20=EB=B0=9B=EC=95=84=EC=84=9C=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdsc/domain/study/domain/StudyDetailTest.java | 7 +++---- .../java/com/gdschongik/gdsc/helper/FixtureHelper.java | 5 +---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailTest.java b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailTest.java index 8118f4a1f..13592767f 100644 --- a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailTest.java +++ b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailTest.java @@ -21,12 +21,11 @@ class 과제_휴강_처리시 { // given Member mentor = fixtureHelper.createAssociateMember(1L); LocalDateTime now = LocalDateTime.now(); - StudyDetail studyDetail = fixtureHelper.createStudyDetail( + Study study = fixtureHelper.createStudy( mentor, Period.createPeriod(now.plusDays(5), now.plusDays(10)), - Period.createPeriod(now.minusDays(5), now), - now, - now.plusDays(7)); + Period.createPeriod(now.minusDays(5), now)); + StudyDetail studyDetail = fixtureHelper.createStudyDetail(study, now, now.plusDays(7)); // when studyDetail.cancelAssignment(); diff --git a/src/test/java/com/gdschongik/gdsc/helper/FixtureHelper.java b/src/test/java/com/gdschongik/gdsc/helper/FixtureHelper.java index 379da313c..f6a4c1cdf 100644 --- a/src/test/java/com/gdschongik/gdsc/helper/FixtureHelper.java +++ b/src/test/java/com/gdschongik/gdsc/helper/FixtureHelper.java @@ -81,10 +81,7 @@ public Study createStudy(Member mentor, Period period, Period applicationPeriod) STUDY_END_TIME); } - public StudyDetail createStudyDetail( - Member mentor, Period period, Period applicationPeriod, LocalDateTime startDate, LocalDateTime endDate) { - Study study = createStudy(mentor, period, applicationPeriod); - + public StudyDetail createStudyDetail(Study study, LocalDateTime startDate, LocalDateTime endDate) { return StudyDetail.createStudyDetail(study, 1L, ATTENDANCE_NUMBER, Period.createPeriod(startDate, endDate)); } } From 60d880d99d139b9272faf774f7abd2d569977e3f Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 2 Aug 2024 19:39:57 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat:=20=ED=98=84=EC=9E=AC=20=EB=A9=A4?= =?UTF-8?q?=EB=B2=84=EC=9D=98=20=EB=A9=98=ED=86=A0=20=EC=97=AC=EB=B6=80=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/application/StudyMentorService.java | 5 +++ .../study/domain/StudyDetailValidator.java | 17 ++++++++ .../gdsc/global/exception/ErrorCode.java | 1 + .../domain/StudyDetailValidatorTest.java | 40 +++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidator.java create mode 100644 src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidatorTest.java diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java index af2d57165..1ddc15f89 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java @@ -16,14 +16,19 @@ @Transactional(readOnly = true) public class StudyMentorService { + private final MemberUtil memberUtil; private final StudyDetailRepository studyDetailRepository; + private final StudyDetailValidator studyDetailValidator; @Transactional public void cancelStudyAssignment(Long studyDetailId) { + Member currentMember = memberUtil.getCurrentMember(); StudyDetail studyDetail = studyDetailRepository .findById(studyDetailId) .orElseThrow(() -> new CustomException(STUDY_DETAIL_NOT_FOUND)); + studyDetailValidator.validateCancelStudyAssignment(currentMember, studyDetail); + studyDetail.cancelAssignment(); log.info("[StudyMentorService] 과제 휴강 처리: studyDetailId={}", studyDetail.getId()); diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidator.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidator.java new file mode 100644 index 000000000..fe38d6bcf --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidator.java @@ -0,0 +1,17 @@ +package com.gdschongik.gdsc.domain.study.domain; + +import com.gdschongik.gdsc.domain.member.domain.Member; +import com.gdschongik.gdsc.global.annotation.DomainService; +import com.gdschongik.gdsc.global.exception.CustomException; +import com.gdschongik.gdsc.global.exception.ErrorCode; + +@DomainService +public class StudyDetailValidator { + + public void validateCancelStudyAssignment(Member currentMember, StudyDetail studyDetail) { + // 멘토가 아니라면 과제를 휴강처리 할 수 없다. + if (!currentMember.equals(studyDetail.getStudy().getMentor())) { + throw new CustomException(ErrorCode.STUDY_DETAIL_NOT_MODIFIABLE_INVALID_ROLE); + } + } +} diff --git a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java index d91f181d2..34fc6d2d0 100644 --- a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java +++ b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java @@ -111,6 +111,7 @@ public enum ErrorCode { // StudyDetail STUDY_DETAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 상세정보입니다."), + STUDY_DETAIL_NOT_MODIFIABLE_INVALID_ROLE(HttpStatus.FORBIDDEN, "수정할 수 있는 권한이 없습니다."), // StudyHistory STUDY_HISTORY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 수강 기록입니다."), diff --git a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidatorTest.java b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidatorTest.java new file mode 100644 index 000000000..0c933bc6c --- /dev/null +++ b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidatorTest.java @@ -0,0 +1,40 @@ +package com.gdschongik.gdsc.domain.study.domain; + +import static com.gdschongik.gdsc.global.exception.ErrorCode.*; +import static org.assertj.core.api.Assertions.*; + +import com.gdschongik.gdsc.domain.member.domain.Member; +import com.gdschongik.gdsc.domain.recruitment.domain.vo.Period; +import com.gdschongik.gdsc.global.exception.CustomException; +import com.gdschongik.gdsc.helper.FixtureHelper; +import java.time.LocalDateTime; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class StudyDetailValidatorTest { + + FixtureHelper fixtureHelper = new FixtureHelper(); + StudyDetailValidator studyDetailValidator = new StudyDetailValidator(); + + @Nested + class 과제_휴강_처리시 { + + @Test + void 멘토가_아니라면_실패한다() { + // given + LocalDateTime now = LocalDateTime.now(); + Member mentor = fixtureHelper.createAssociateMember(1L); + Study study = fixtureHelper.createStudy( + mentor, + Period.createPeriod(now.plusDays(5), now.plusDays(10)), + Period.createPeriod(now.minusDays(5), now)); + StudyDetail studyDetail = fixtureHelper.createStudyDetail(study, now, now.plusDays(7)); + Member anotherMember = fixtureHelper.createAssociateMember(2L); + + // when & then + assertThatThrownBy(() -> studyDetailValidator.validateCancelStudyAssignment(anotherMember, studyDetail)) + .isInstanceOf(CustomException.class) + .hasMessage(STUDY_DETAIL_NOT_MODIFIABLE_INVALID_ROLE.getMessage()); + } + } +} From bac85e6d4eee787b7396446d7ab15ccbed824228 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 2 Aug 2024 19:40:23 +0900 Subject: [PATCH 06/10] =?UTF-8?q?refactor:=20save=20=ED=98=B8=EC=B6=9C?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdsc/domain/study/application/StudyMentorService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java index 1ddc15f89..2035b15c9 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java @@ -2,9 +2,12 @@ import static com.gdschongik.gdsc.global.exception.ErrorCode.*; +import com.gdschongik.gdsc.domain.member.domain.Member; import com.gdschongik.gdsc.domain.study.dao.StudyDetailRepository; import com.gdschongik.gdsc.domain.study.domain.StudyDetail; +import com.gdschongik.gdsc.domain.study.domain.StudyDetailValidator; import com.gdschongik.gdsc.global.exception.CustomException; +import com.gdschongik.gdsc.global.util.MemberUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -30,6 +33,7 @@ public void cancelStudyAssignment(Long studyDetailId) { studyDetailValidator.validateCancelStudyAssignment(currentMember, studyDetail); studyDetail.cancelAssignment(); + studyDetailRepository.save(studyDetail); log.info("[StudyMentorService] 과제 휴강 처리: studyDetailId={}", studyDetail.getId()); } From dac5ae80827d90437c5edaaf83418b25e34600bd Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 2 Aug 2024 19:50:29 +0900 Subject: [PATCH 07/10] =?UTF-8?q?fix:=20=EC=8B=9C=ED=81=90=EB=A6=AC?= =?UTF-8?q?=ED=8B=B0=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdsc/domain/study/application/StudyMentorServiceTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java b/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java index 1cd4285b8..1cc5581e3 100644 --- a/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java +++ b/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.*; +import com.gdschongik.gdsc.domain.member.domain.MemberRole; import com.gdschongik.gdsc.domain.study.dao.StudyDetailRepository; import com.gdschongik.gdsc.domain.study.domain.StudyDetail; import com.gdschongik.gdsc.domain.study.domain.StudyStatus; @@ -27,6 +28,7 @@ class 스터디_과제_휴강_처리시 { // given LocalDateTime now = LocalDateTime.now(); StudyDetail studyDetail = createStudyDetail(now, now.plusDays(7)); + logoutAndReloginAs(studyDetail.getStudy().getMentor().getId(), MemberRole.ASSOCIATE); // when studyMentorService.cancelStudyAssignment(studyDetail.getId()); From 166edd4858f431921904a5312918bd734a24c974 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 2 Aug 2024 21:30:12 +0900 Subject: [PATCH 08/10] =?UTF-8?q?remove:=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EB=A0=88=EB=B2=A8=20=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=94?= =?UTF-8?q?=EB=84=90=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdsc/domain/study/application/StudyMentorService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java index fce5d5e9e..df839c803 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyMentorService.java @@ -18,7 +18,6 @@ @Slf4j @Service @RequiredArgsConstructor -@Transactional(readOnly = true) public class StudyMentorService { private final MemberUtil memberUtil; From 23603ce912d0b6f49495d099f8f35cfcf33e1801 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 2 Aug 2024 22:02:07 +0900 Subject: [PATCH 09/10] =?UTF-8?q?refactor:=20=ED=98=84=EB=A9=A4=EB=B2=84?= =?UTF-8?q?=EC=9D=98=20=EB=A9=98=ED=86=A0=20=EC=97=AC=EB=B6=80=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=EC=9D=84=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EB=A1=9C=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdsc/domain/study/domain/StudyDetailValidator.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidator.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidator.java index fe38d6bcf..ea9992eb7 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidator.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetailValidator.java @@ -9,8 +9,12 @@ public class StudyDetailValidator { public void validateCancelStudyAssignment(Member currentMember, StudyDetail studyDetail) { - // 멘토가 아니라면 과제를 휴강처리 할 수 없다. - if (!currentMember.equals(studyDetail.getStudy().getMentor())) { + validateMemberIsMentor(currentMember, studyDetail); + } + + // 멘토가 아니라면 과제를 휴강처리 할 수 없다. + private void validateMemberIsMentor(Member member, StudyDetail studyDetail) { + if (!member.equals(studyDetail.getStudy().getMentor())) { throw new CustomException(ErrorCode.STUDY_DETAIL_NOT_MODIFIABLE_INVALID_ROLE); } } From 151cf827d28149e8783dcc6c04e3879f44b3ab2f Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 2 Aug 2024 22:11:15 +0900 Subject: [PATCH 10/10] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=84=B0=EB=94=94?= =?UTF-8?q?=EB=A5=BC=20=EC=A3=BC=EC=9E=85=EB=B0=9B=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/application/StudyMentorServiceTest.java | 10 +++++++++- .../com/gdschongik/gdsc/helper/IntegrationTest.java | 9 +-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java b/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java index 1cc5581e3..c4ecb95ff 100644 --- a/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java +++ b/src/test/java/com/gdschongik/gdsc/domain/study/application/StudyMentorServiceTest.java @@ -2,8 +2,11 @@ import static org.assertj.core.api.Assertions.*; +import com.gdschongik.gdsc.domain.member.domain.Member; import com.gdschongik.gdsc.domain.member.domain.MemberRole; +import com.gdschongik.gdsc.domain.recruitment.domain.vo.Period; import com.gdschongik.gdsc.domain.study.dao.StudyDetailRepository; +import com.gdschongik.gdsc.domain.study.domain.Study; import com.gdschongik.gdsc.domain.study.domain.StudyDetail; import com.gdschongik.gdsc.domain.study.domain.StudyStatus; import com.gdschongik.gdsc.helper.IntegrationTest; @@ -27,7 +30,12 @@ class 스터디_과제_휴강_처리시 { void 성공한다() { // given LocalDateTime now = LocalDateTime.now(); - StudyDetail studyDetail = createStudyDetail(now, now.plusDays(7)); + Member mentor = createAssociateMember(); + Study study = createStudy( + mentor, + Period.createPeriod(now.plusDays(5), now.plusDays(10)), + Period.createPeriod(now.minusDays(5), now)); + StudyDetail studyDetail = createStudyDetail(study, now, now.plusDays(7)); logoutAndReloginAs(studyDetail.getStudy().getMentor().getId(), MemberRole.ASSOCIATE); // when diff --git a/src/test/java/com/gdschongik/gdsc/helper/IntegrationTest.java b/src/test/java/com/gdschongik/gdsc/helper/IntegrationTest.java index 4053200d5..ee4635223 100644 --- a/src/test/java/com/gdschongik/gdsc/helper/IntegrationTest.java +++ b/src/test/java/com/gdschongik/gdsc/helper/IntegrationTest.java @@ -188,14 +188,7 @@ protected Study createStudy(Member mentor, Period period, Period applicationPeri return studyRepository.save(study); } - protected StudyDetail createStudyDetail(LocalDateTime startDate, LocalDateTime endDate) { - Member mentor = createAssociateMember(); - LocalDateTime now = LocalDateTime.now(); - Study study = createStudy( - mentor, - Period.createPeriod(now.plusDays(5), now.plusDays(10)), - Period.createPeriod(now.minusDays(5), now)); - + protected StudyDetail createStudyDetail(Study study, LocalDateTime startDate, LocalDateTime endDate) { StudyDetail studyDetail = StudyDetail.createStudyDetail(study, 1L, ATTENDANCE_NUMBER, Period.createPeriod(startDate, endDate)); return studyDetailRepository.save(studyDetail);