Skip to content
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 추가 #542

Merged
merged 11 commits into from
Aug 2, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class StudyMentorController {
private final StudyMentorService studyMentorService;

@Operation(summary = "스터디 과제 개설", description = "멘토만 과제를 개설할 수 있습니다.")
@PutMapping("/assignment/{assignmentId}")
@PutMapping("/assignments/{assignmentId}")
public ResponseEntity<Void> createStudyAssignment(
@PathVariable Long assignmentId, @Valid @RequestBody AssignmentCreateRequest request) {
return null;
Expand All @@ -39,4 +39,11 @@ public ResponseEntity<AssignmentResponse> getStudyAssignment(@PathVariable Long
AssignmentResponse response = studyMentorService.getAssignment(studyDetailId);
return ResponseEntity.ok(response);
}

@Operation(summary = "스터디 과제 휴강 처리", description = "해당 주차 과제를 휴강 처리합니다.")
@PatchMapping("/assignments/{studyDetailId}/cancel")
public ResponseEntity<Void> cancelStudyAssignment(@PathVariable Long studyDetailId) {
studyMentorService.cancelStudyAssignment(studyDetailId);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

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.domain.study.dto.response.AssignmentResponse;
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;
Expand All @@ -17,7 +20,9 @@
@RequiredArgsConstructor
public class StudyMentorService {

private final MemberUtil memberUtil;
private final StudyDetailRepository studyDetailRepository;
private final StudyDetailValidator studyDetailValidator;

@Transactional(readOnly = true)
public List<AssignmentResponse> getWeeklyAssignments(Long studyId) {
Expand All @@ -32,4 +37,19 @@ public AssignmentResponse getAssignment(Long studyDetailId) {
.orElseThrow(() -> new CustomException(STUDY_DETAIL_NOT_FOUND));
return AssignmentResponse.from(studyDetail);
}

@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();
Sangwook02 marked this conversation as resolved.
Show resolved Hide resolved
studyDetailRepository.save(studyDetail);

log.info("[StudyMentorService] 과제 휴강 처리: studyDetailId={}", studyDetail.getId());
}
Sangwook02 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,8 @@ public static StudyDetail createStudyDetail(Study study, Long week, String atten
.assignment(Assignment.createEmptyAssignment())
.build();
}

public void cancelAssignment() {
assignment = Assignment.cancelAssignment();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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) {
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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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, "존재하지 않는 스터디 수강 기록입니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.gdschongik.gdsc.domain.study.application;

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;
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();
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
studyMentorService.cancelStudyAssignment(studyDetail.getId());

// then
StudyDetail cancelledStudyDetail =
studyDetailRepository.findById(studyDetail.getId()).get();
assertThat(cancelledStudyDetail.getAssignment().getStatus()).isEqualTo(StudyStatus.CANCELLED);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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();
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));

// when
studyDetail.cancelAssignment();

// then
assertThat(studyDetail.getAssignment().getStatus()).isEqualTo(StudyStatus.CANCELLED);
}
}
}
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
5 changes: 5 additions & 0 deletions src/test/java/com/gdschongik/gdsc/helper/FixtureHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -79,4 +80,8 @@ public Study createStudy(Member mentor, Period period, Period applicationPeriod)
STUDY_START_TIME,
STUDY_END_TIME);
}

public StudyDetail createStudyDetail(Study study, LocalDateTime startDate, LocalDateTime endDate) {
return StudyDetail.createStudyDetail(study, 1L, ATTENDANCE_NUMBER, Period.createPeriod(startDate, endDate));
}
}
33 changes: 33 additions & 0 deletions src/test/java/com/gdschongik/gdsc/helper/IntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -62,6 +67,12 @@ public abstract class IntegrationTest {
@Autowired
protected RecruitmentRoundRepository recruitmentRoundRepository;

@Autowired
protected StudyRepository studyRepository;

@Autowired
protected StudyDetailRepository studyDetailRepository;

@MockBean
protected OnboardingRecruitmentService onboardingRecruitmentService;

Expand Down Expand Up @@ -160,4 +171,26 @@ 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(Study study, LocalDateTime startDate, LocalDateTime endDate) {
StudyDetail studyDetail =
StudyDetail.createStudyDetail(study, 1L, ATTENDANCE_NUMBER, Period.createPeriod(startDate, endDate));
return studyDetailRepository.save(studyDetail);
}
}