Skip to content

Commit

Permalink
feat: 스터디 수료 및 철회 API 구현 (#819)
Browse files Browse the repository at this point in the history
* feat: 스터디 수료 및 철회 api 구현

* fix: api 설명 수정

* fix: 로그 수정

* fix: 수강 이력 조회 시 studyId를 이용하도록 수정

* fix: valid 어노테이션 제거

* feat: studyId를 dto에 포함

* fix: post 요청으로 변경
  • Loading branch information
Sangwook02 authored Nov 12, 2024
1 parent 0e1612f commit 5fc0d43
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.gdschongik.gdsc.domain.study.dto.request.OutstandingStudentRequest;
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.DeleteMapping;
Expand All @@ -25,15 +24,15 @@ public class MentorStudyAchievementController {
@Operation(summary = "우수 스터디원 지정", description = "우수 스터디원으로 지정합니다.")
@PostMapping
public ResponseEntity<Void> designateOutstandingStudent(
@RequestParam(name = "studyId") Long studyId, @Valid @RequestBody OutstandingStudentRequest request) {
@RequestParam(name = "studyId") Long studyId, @RequestBody OutstandingStudentRequest request) {
mentorStudyAchievementService.designateOutstandingStudent(studyId, request);
return ResponseEntity.ok().build();
}

@Operation(summary = "우수 스터디원 철회", description = "우수 스터디원 지정을 철회합니다.")
@DeleteMapping
public ResponseEntity<Void> withdrawOutstandingStudent(
@RequestParam(name = "studyId") Long studyId, @Valid @RequestBody OutstandingStudentRequest request) {
@RequestParam(name = "studyId") Long studyId, @RequestBody OutstandingStudentRequest request) {
mentorStudyAchievementService.withdrawOutstandingStudent(studyId, request);
return ResponseEntity.ok().build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.gdschongik.gdsc.domain.study.api;

import com.gdschongik.gdsc.domain.study.application.MentorStudyHistoryService;
import com.gdschongik.gdsc.domain.study.dto.request.StudyCompleteRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
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 = "스터디 수료 처리합니다.")
@PostMapping("/complete")
public ResponseEntity<Void> completeStudy(@RequestBody StudyCompleteRequest request) {
mentorStudyHistoryService.completeStudy(request);
return ResponseEntity.ok().build();
}

@Operation(summary = "스터디 수료 철회", description = "스터디 수료 처리를 철회합니다.")
@PostMapping("/withdraw-completion")
public ResponseEntity<Void> withdrawStudyCompletion(@RequestBody StudyCompleteRequest request) {
mentorStudyHistoryService.withdrawStudyCompletion(request);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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.StudyCompleteRequest;
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(StudyCompleteRequest request) {
Member currentMember = memberUtil.getCurrentMember();
Study study =
studyRepository.findById(request.studyId()).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND));
List<StudyHistory> studyHistories =
studyHistoryRepository.findAllByStudyIdAndStudentIds(request.studyId(), request.studentIds());

studyValidator.validateStudyMentor(currentMember, study);
studyHistoryValidator.validateAppliedToStudy(
studyHistories.size(), request.studentIds().size());

studyHistories.forEach(StudyHistory::complete);

log.info(
"[MentorStudyHistoryService] 스터디 수료 처리: studyId={}, studentIds={}",
request.studyId(),
request.studentIds());
}

@Transactional
public void withdrawStudyCompletion(StudyCompleteRequest request) {
Member currentMember = memberUtil.getCurrentMember();
Study study =
studyRepository.findById(request.studyId()).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND));
List<StudyHistory> studyHistories =
studyHistoryRepository.findAllByStudyIdAndStudentIds(request.studyId(), request.studentIds());

studyValidator.validateStudyMentor(currentMember, study);
studyHistoryValidator.validateAppliedToStudy(
studyHistories.size(), request.studentIds().size());

studyHistories.forEach(StudyHistory::withdrawCompletion);

log.info(
"[MentorStudyHistoryService] 스터디 수료 철회: studyId={}, studentIds={}",
request.studyId(),
request.studentIds());
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.gdschongik.gdsc.domain.study.dao;

import com.gdschongik.gdsc.domain.study.domain.StudyHistory;
import java.util.List;

public interface StudyHistoryCustomRepository {

long countByStudyIdAndStudentIds(Long studyId, List<Long> studentIds);

List<StudyHistory> findAllByStudyIdAndStudentIds(Long studyId, List<Long> studentIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.gdschongik.gdsc.domain.study.domain.QStudyHistory.*;

import com.gdschongik.gdsc.domain.study.domain.StudyHistory;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
Expand All @@ -21,6 +22,14 @@ public long countByStudyIdAndStudentIds(Long studyId, List<Long> studentIds) {
.fetchOne();
}

@Override
public List<StudyHistory> findAllByStudyIdAndStudentIds(Long studyId, List<Long> studentIds) {
return queryFactory
.selectFrom(studyHistory)
.where(eqStudyId(studyId), studyHistory.student.id.in(studentIds))
.fetch();
}

private BooleanExpression eqStudyId(Long studyId) {
return studyHistory.study.id.eq(studyId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ public void complete() {
studyHistoryStatus = COMPLETED;
}

/**
* 스터디 수료 철회
*/
public void withdrawCompletion() {
studyHistoryStatus = NONE;
}

// 데이터 전달 로직
public boolean isWithinApplicationAndCourse() {
return study.isWithinApplicationAndCourse();
Expand Down
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 StudyCompleteRequest(Long studyId, List<Long> studentIds) {}
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,27 @@ class 스터디_수료시 {
assertThat(studyHistory.getStudyHistoryStatus()).isEqualTo(COMPLETED);
}
}

@Nested
class 스터디_수료_철회시 {

@Test
void 수료상태는_NONE이다() {
// given
Member student = fixtureHelper.createRegularMember(1L);
Member mentor = fixtureHelper.createRegularMember(2L);
LocalDateTime now = LocalDateTime.now();
Study study = fixtureHelper.createStudy(
mentor, Period.of(now.plusDays(5), now.plusDays(10)), Period.of(now.minusDays(5), now));

StudyHistory studyHistory = StudyHistory.create(student, study);
studyHistory.complete();

// when
studyHistory.withdrawCompletion();

// then
assertThat(studyHistory.getStudyHistoryStatus()).isEqualTo(NONE);
}
}
}

0 comments on commit 5fc0d43

Please sign in to comment.