Skip to content

Commit

Permalink
feat: 수강신청 철회 시 연관 엔티티도 같이 삭제하도록 변경 (#757)
Browse files Browse the repository at this point in the history
* feat: 수강철회 시 이벤트 발행

* feat: 이벤트 핸들러 및 공통 스터디 서비스 로직 추가

* feat: 삭제 로직 구현

* docs: todo 추가
  • Loading branch information
uwoobeat authored Sep 4, 2024
1 parent aee0968 commit 83cc9a9
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.gdschongik.gdsc.domain.study.application;

import static com.gdschongik.gdsc.global.exception.ErrorCode.STUDY_NOT_FOUND;
import static com.gdschongik.gdsc.global.exception.ErrorCode.*;

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.dao.AssignmentHistoryRepository;
import com.gdschongik.gdsc.domain.study.dao.AttendanceRepository;
import com.gdschongik.gdsc.domain.study.dao.StudyAnnouncementRepository;
import com.gdschongik.gdsc.domain.study.dao.StudyHistoryRepository;
import com.gdschongik.gdsc.domain.study.dao.StudyRepository;
Expand All @@ -29,6 +31,8 @@ public class CommonStudyService {
private final StudyRepository studyRepository;
private final StudyHistoryRepository studyHistoryRepository;
private final StudyAnnouncementRepository studyAnnouncementRepository;
private final AttendanceRepository attendanceRepository;
private final AssignmentHistoryRepository assignmentHistoryRepository;
private final MemberUtil memberUtil;
private final StudyValidator studyValidator;

Expand All @@ -51,4 +55,26 @@ public List<StudyAnnouncementResponse> getStudyAnnouncements(Long studyId) {

return studyAnnouncements.stream().map(StudyAnnouncementResponse::from).toList();
}

/**
* 이벤트 핸들러에서 사용되므로, `@Transactional` 을 사용하지 않습니다.
*/
public void deleteAttendanceByStudyHistory(Long studyHistoryId) {
StudyHistory studyHistory = studyHistoryRepository
.findById(studyHistoryId)
.orElseThrow(() -> new CustomException(STUDY_HISTORY_NOT_FOUND));

attendanceRepository.deleteByStudyHistory(studyHistory);
}

/**
* 이벤트 핸들러에서 사용되므로, `@Transactional` 을 사용하지 않습니다.
*/
public void deleteAssignmentHistoryByStudyHistory(Long studyHistoryId) {
StudyHistory studyHistory = studyHistoryRepository
.findById(studyHistoryId)
.orElseThrow(() -> new CustomException(STUDY_HISTORY_NOT_FOUND));

assignmentHistoryRepository.deleteByStudyHistory(studyHistory);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public void applyStudy(Long studyId) {

@Transactional
public void cancelStudyApply(Long studyId) {
// TODO: 통합 테스트 통해 수강철회 관련 이벤트 처리 확인
Study study = studyRepository.findById(studyId).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND));
Member currentMember = memberUtil.getCurrentMember();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.gdschongik.gdsc.domain.study.application;

import com.gdschongik.gdsc.domain.study.domain.StudyApplyCanceledEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

@Slf4j
@Component
@RequiredArgsConstructor
public class StudyEventHandler {

private final CommonStudyService commonStudyService;

@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleStudyApplyCanceledEvent(StudyApplyCanceledEvent event) {
log.info("[StudyEventHandler] 스터디 수강신청 취소 이벤트 수신: studyHistoryId={}", event.studyHistoryId());
commonStudyService.deleteAttendanceByStudyHistory(event.studyHistoryId());
commonStudyService.deleteAssignmentHistoryByStudyHistory(event.studyHistoryId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.domain.AssignmentHistory;
import com.gdschongik.gdsc.domain.study.domain.Study;
import com.gdschongik.gdsc.domain.study.domain.StudyHistory;
import java.util.List;

public interface AssignmentHistoryCustomRepository {

boolean existsSubmittedAssignmentByMemberAndStudy(Member member, Study study);

List<AssignmentHistory> findAssignmentHistoriesByStudentAndStudyId(Member member, Long studyId);

void deleteByStudyHistory(StudyHistory studyHistory);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.domain.AssignmentHistory;
import com.gdschongik.gdsc.domain.study.domain.Study;
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 Down Expand Up @@ -53,4 +54,12 @@ public List<AssignmentHistory> findAssignmentHistoriesByStudentAndStudyId(Member
private BooleanExpression eqStudyId(Long studyId) {
return studyId != null ? studyDetail.study.id.eq(studyId) : null;
}

@Override
public void deleteByStudyHistory(StudyHistory studyHistory) {
queryFactory
.delete(assignmentHistory)
.where(eqMember(studyHistory.getStudent()).and(eqStudy(studyHistory.getStudy())))
.execute();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

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

public interface AttendanceCustomRepository {
List<Attendance> findByMemberAndStudyId(Member member, Long studyId);

void deleteByStudyHistory(StudyHistory studyHistory);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.domain.Attendance;
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 Down Expand Up @@ -33,4 +34,15 @@ private BooleanExpression eqMemberId(Long memberId) {
private BooleanExpression eqStudyId(Long studyId) {
return studyId != null ? attendance.studyDetail.study.id.eq(studyId) : null;
}

@Override
public void deleteByStudyHistory(StudyHistory studyHistory) {
queryFactory
.delete(attendance)
.where(attendance
.student
.eq(studyHistory.getStudent())
.and(attendance.studyDetail.study.eq(studyHistory.getStudy())))
.execute();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.gdschongik.gdsc.domain.study.domain;

public record StudyApplyCanceledEvent(Long studyHistoryId) {}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.PreRemove;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import lombok.AccessLevel;
Expand Down Expand Up @@ -48,6 +49,11 @@ public static StudyHistory create(Member student, Study study) {
return StudyHistory.builder().student(student).study(study).build();
}

@PreRemove
private void preRemove() {
registerEvent(new StudyApplyCanceledEvent(this.id));
}

/**
* 레포지토리 링크를 업데이트합니다.
*/
Expand Down

0 comments on commit 83cc9a9

Please sign in to comment.