Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.chzzk.howmeet.domain.regular.room.repository;

import org.chzzk.howmeet.domain.regular.room.dto.get.response.RoomMemberGetResponse;
import org.chzzk.howmeet.domain.regular.room.entity.RoomMember;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
Expand All @@ -14,4 +16,9 @@ public interface RoomMemberRepository extends JpaRepository<RoomMember, Long> {
Page<RoomMember> findByMemberId(Long memberId, Pageable pageable);
Optional<RoomMember> findByRoomIdAndMemberId(@Param("roomId") final Long roomId, @Param("memberId") final Long memberId);
boolean existsByRoomIdAndMemberId(Long roomId, Long memberId);

@Query("SELECT new org.chzzk.howmeet.domain.regular.room.dto.get.response.RoomMemberGetResponse(rm.isLeader) " +
"FROM RoomMember rm " +
"WHERE rm.room.id = :roomId AND rm.memberId = :memberId")
Optional<RoomMemberGetResponse> findRoomMemberGetResponseByRoomIdAndMemberId(@Param("roomId") Long roomId, @Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.chzzk.howmeet.domain.regular.room.entity.Room;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

Expand All @@ -13,4 +14,10 @@ public interface RoomRepository extends JpaRepository<Room, Long> {
"LEFT JOIN Member m ON m.id = rm.memberId " +
"WHERE r.id = :roomId")
Optional<Room> findRoomWithMembersAndNicknames(@Param("roomId") Long roomId);

@Modifying
@Query("UPDATE Room r SET r.disable = true WHERE r.id = :roomId")
void disableRoomById(@Param("roomId") Long roomId);

boolean existsByIdAndDisableFalse(Long roomId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public class RoomMemberService {
private final RoomRepository roomRepository;

public RoomMemberGetResponse getRoomMember(final AuthPrincipal authPrincipal, final Long roomId) {
final RoomMember roomMember = findRoomMemberByAuthAndRoomId(authPrincipal, roomId);
return RoomMemberGetResponse.from(roomMember);
return roomMemberRepository.findRoomMemberGetResponseByRoomIdAndMemberId(roomId, authPrincipal.id())
.orElseThrow(() -> new RoomMemberException(ROOM_NOT_FOUND));
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,11 @@ public void updateRoom(final Long roomId, final RoomRequest roomRequest) {

@Transactional
public void deleteRoom(final Long roomId) {
Room room = getRoomById(roomId);
roomRepository.delete(room);
if (!roomRepository.existsByIdAndDisableFalse(roomId)) {
throw new RoomException(ROOM_NOT_FOUND);
}

roomRepository.disableRoomById(roomId);
}

private RoomListResponse mapToRoomListResponse(RoomMember roomMember) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
package org.chzzk.howmeet.domain.regular.schedule.repository;

import org.chzzk.howmeet.domain.regular.room.entity.Room;
import org.chzzk.howmeet.domain.regular.schedule.dto.CompletedMSResponse;
import org.chzzk.howmeet.domain.regular.schedule.dto.ProgressedMSResponse;
import org.chzzk.howmeet.domain.regular.schedule.entity.MemberSchedule;
import org.chzzk.howmeet.domain.regular.schedule.entity.ScheduleStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

public interface MSRepository extends JpaRepository<MemberSchedule, Long> {
Optional<MemberSchedule> findByIdAndRoomId(Long msId, Long roomId);

@Query("SELECT ms.status FROM MemberSchedule ms WHERE ms.id = :msId AND ms.room.id = :roomId")
Optional<ScheduleStatus> findStatusByIdAndRoomId(@Param("msId") Long msId, @Param("roomId") Long roomId);

@Modifying
@Transactional
@Query("UPDATE MemberSchedule ms SET ms.disable = true WHERE ms.id = :msId AND ms.room.id = :roomId")
void deactivateMemberSchedule(@Param("msId") Long msId, @Param("roomId") Long roomId);

@Query("SELECT new org.chzzk.howmeet.domain.regular.schedule.dto.ProgressedMSResponse(ms.id, ms.dates, ms.time, ms.name, ms.status) " +
"FROM MemberSchedule ms WHERE ms.id = :msId AND ms.room.id = :roomId AND ms.status = 'PROGRESS'")
Optional<ProgressedMSResponse> findProgressScheduleDto(@Param("msId") Long msId, @Param("roomId") Long roomId);

boolean existsByIdAndRoomId(Long msId, Long roomId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,46 @@ public MSCreateResponse createMemberSchedule(final Long roomId, final MSRequest
.orElseThrow(() -> new MSException(ROOM_NOT_FOUND));

MemberSchedule memberSchedule = msRequest.toEntity(room);
MemberSchedule savedSchedule = msRepository.save(memberSchedule);

return MSCreateResponse.from(room);
}

public MSResponse getMemberSchedule(final Long roomId, final Long msId) {
MemberSchedule memberSchedule = findMemberScheduleByRoomIdAndMsId(roomId, msId);
ScheduleStatus status = msRepository.findStatusByIdAndRoomId(msId, roomId)
.orElseThrow(() -> new MSException(SCHEDULE_NOT_FOUND));

if (memberSchedule.getStatus() == ScheduleStatus.COMPLETE) {
// Todo complete 경우에는 후처리가 필요한데 dto를 하나더 만들어서 가져와서 변환하는게 맞는지
if (status == ScheduleStatus.COMPLETE) {
MemberSchedule memberSchedule = findMemberScheduleByRoomIdAndMsId(roomId, msId);
ConfirmSchedule confirmSchedule = findConfirmScheduleByMSId(msId);
List<LocalDateTime> confirmTimes = confirmSchedule.getTimes();
List<String> dates = extractDatesFromConfirmTimes(confirmTimes);
ScheduleTime scheduleTime = extractScheduleTimeFromConfirmTimes(confirmTimes);
return CompletedMSResponse.of(memberSchedule, dates, scheduleTime);
} else if (memberSchedule.getStatus() == ScheduleStatus.PROGRESS) {
return ProgressedMSResponse.from(memberSchedule);
} else if (status == ScheduleStatus.PROGRESS) {
return msRepository.findProgressScheduleDto(msId, roomId)
.orElseThrow(() -> new MSException(SCHEDULE_NOT_FOUND));
}

throw new IllegalStateException("알 수 없는 상태입니다.");
}

@Transactional
public void deleteMemberSchedule(final Long roomId, final Long msId) {
MemberSchedule memberSchedule = findMemberScheduleByRoomIdAndMsId(roomId, msId);
memberSchedule.deactivate();
msRepository.save(memberSchedule);
if (!msRepository.existsByIdAndRoomId(msId, roomId)) {
// 예외 수정 필요
throw new MSException(SCHEDULE_NOT_FOUND);
}
msRepository.deactivateMemberSchedule(msId, roomId);
}

// Todo repository
private MemberSchedule findMemberScheduleByRoomIdAndMsId(Long roomId, Long msId) {
return msRepository.findByIdAndRoomId(msId, roomId)
.orElseThrow(() -> new MSException(SCHEDULE_NOT_FOUND));
}

// Todo repository
private ConfirmSchedule findConfirmScheduleByMSId(Long memberScheduleId) {
return confirmRepository.findByMemberScheduleId(memberScheduleId)
.orElseThrow(() -> new IllegalArgumentException("일치하는 일정 결과를 찾을 수 없습니다."));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
package org.chzzk.howmeet.domain.temporary.schedule.repository;

import org.chzzk.howmeet.domain.regular.schedule.entity.ScheduleStatus;
import org.chzzk.howmeet.domain.temporary.schedule.dto.GSResponse;
import org.chzzk.howmeet.domain.temporary.schedule.entity.GuestSchedule;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

public interface GSRepository extends JpaRepository<GuestSchedule, Long>, GSQueryDSL {
List<GuestSchedule> findByStatusAndCreatedAtBefore(ScheduleStatus status, LocalDateTime cutoffDate);
List<GuestSchedule> findByStatusAndUpdatedAtBefore(ScheduleStatus status, LocalDateTime cutoffDate);
@Query("SELECT gs.id FROM GuestSchedule gs WHERE gs.status = :status AND gs.createdAt < :cutoffDate")
List<Long> findIdsByStatusAndCreatedAtBefore(@Param("status") ScheduleStatus status, @Param("cutoffDate") LocalDateTime cutoffDate);
@Query("SELECT gs.id FROM GuestSchedule gs WHERE gs.status = :status AND gs.updatedAt < :cutoffDate")
List<Long> findIdsByStatusAndUpdatedAtBefore(@Param("status") ScheduleStatus status, @Param("cutoffDate") LocalDateTime cutoffDate);

@Query("SELECT new org.chzzk.howmeet.domain.temporary.schedule.dto.GSResponse(gs.id, gs.dates, gs.time, gs.name, gs.status) " +
"FROM GuestSchedule gs WHERE gs.id = :guestScheduleId")
Optional<GSResponse> findGuestScheduleDtoById(@Param("guestScheduleId") Long guestScheduleId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,25 @@ public GSCreateResponse createGuestSchedule(final GSRequest gsRequest) {
}

public GSResponse getGuestSchedule(final Long guestScheduleId) {
GuestSchedule guestSchedule = gsRepository.findById(guestScheduleId)
return gsRepository.findGuestScheduleDtoById(guestScheduleId)
.orElseThrow(() -> new GSException(SCHEDULE_NOT_FOUND));
return GSResponse.of(guestSchedule);
}

@Scheduled(cron = "0 0 0 * * ?")
@Transactional
public void disableOldGuestSchedules() {
LocalDateTime now = LocalDateTime.now();
// PROGRESS 상태인 스케줄 삭제
List<GuestSchedule> progressSchedules = gsRepository.findByStatusAndCreatedAtBefore(ScheduleStatus.PROGRESS, now.minusDays(10));
for (GuestSchedule schedule : progressSchedules) {
List<Long> progressScheduleIds = gsRepository.findIdsByStatusAndCreatedAtBefore(ScheduleStatus.PROGRESS, now.minusDays(10));
for (Long scheduleId : progressScheduleIds) {
GuestSchedule schedule = gsRepository.findById(scheduleId).orElseThrow();
schedule.deactivate();
}

// COMPLETE 상태인 스케줄 삭제
List<GuestSchedule> completeSchedules = gsRepository.findByStatusAndUpdatedAtBefore(ScheduleStatus.COMPLETE, now.minusDays(10));
for (GuestSchedule schedule : completeSchedules) {
List<Long> completeScheduleIds = gsRepository.findIdsByStatusAndUpdatedAtBefore(ScheduleStatus.COMPLETE, now.minusDays(10));
for (Long scheduleId : completeScheduleIds) {
GuestSchedule schedule = gsRepository.findById(scheduleId).orElseThrow();
schedule.deactivate();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,78 +1,78 @@
package org.chzzk.howmeet.domain.temporary.schedule.service;

import org.chzzk.howmeet.domain.regular.schedule.entity.ScheduleStatus;
import org.chzzk.howmeet.domain.temporary.schedule.entity.GuestSchedule;
import org.chzzk.howmeet.domain.temporary.schedule.exception.GSException;
import org.chzzk.howmeet.domain.temporary.schedule.repository.GSRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.chzzk.howmeet.domain.temporary.schedule.exception.GSErrorCode.SCHEDULE_NOT_FOUND;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class GSServiceTest {

@InjectMocks
private GSService gsService;

@Mock
private GSRepository gsRepository;

@Test
@DisplayName("비회원 일정 조회 시 잘못된 ID로 예외 발생")
public void getGuestScheduleWhenInvalidId() {
Long invalidId = 999L;

// when
doReturn(Optional.empty()).when(gsRepository).findById(invalidId);

// then
assertThatThrownBy(() -> gsService.getGuestSchedule(invalidId))
.isInstanceOf(GSException.class)
.hasMessage(SCHEDULE_NOT_FOUND.getMessage());
}

@Test
@DisplayName("10일 이상 지난 PROGRESS 상태의 스케줄 disable 처리")
public void disableProgressGuestSchedule() {
LocalDateTime tenDaysAgo = LocalDateTime.now().minusDays(10);

GuestSchedule progressSchedule = mock(GuestSchedule.class);
lenient().when(progressSchedule.getStatus()).thenReturn(ScheduleStatus.PROGRESS);
lenient().when(progressSchedule.getCreatedAt()).thenReturn(tenDaysAgo); // 10일 전으로 설정

when(gsRepository.findByStatusAndCreatedAtBefore(eq(ScheduleStatus.PROGRESS), any()))
.thenReturn(Collections.singletonList(progressSchedule));

gsService.disableOldGuestSchedules();

verify(progressSchedule).deactivate();
}

@Test
@DisplayName("10일 이상 지난 COMPLETE 상태의 스케줄 disable 처리")
public void disableCompleteGuestSchedule() {
LocalDateTime tenDaysAgo = LocalDateTime.now().minusDays(10);

GuestSchedule completeSchedule = mock(GuestSchedule.class);
lenient().when(completeSchedule.getStatus()).thenReturn(ScheduleStatus.COMPLETE);
lenient().when(completeSchedule.getUpdatedAt()).thenReturn(tenDaysAgo);

when(gsRepository.findByStatusAndUpdatedAtBefore(eq(ScheduleStatus.COMPLETE), any()))
.thenReturn(Collections.singletonList(completeSchedule));

gsService.disableOldGuestSchedules();

verify(completeSchedule).deactivate();
}
}
//package org.chzzk.howmeet.domain.temporary.schedule.service;
//
//import org.chzzk.howmeet.domain.regular.schedule.entity.ScheduleStatus;
//import org.chzzk.howmeet.domain.temporary.schedule.entity.GuestSchedule;
//import org.chzzk.howmeet.domain.temporary.schedule.exception.GSException;
//import org.chzzk.howmeet.domain.temporary.schedule.repository.GSRepository;
//import org.junit.jupiter.api.DisplayName;
//import org.junit.jupiter.api.Test;
//import org.junit.jupiter.api.extension.ExtendWith;
//import org.mockito.InjectMocks;
//import org.mockito.Mock;
//import org.mockito.junit.jupiter.MockitoExtension;
//
//import java.time.LocalDateTime;
//import java.util.Collections;
//import java.util.Optional;
//
//import static org.assertj.core.api.Assertions.assertThatThrownBy;
//import static org.chzzk.howmeet.domain.temporary.schedule.exception.GSErrorCode.SCHEDULE_NOT_FOUND;
//import static org.mockito.Mockito.*;
//
//@ExtendWith(MockitoExtension.class)
//class GSServiceTest {
//
// @InjectMocks
// private GSService gsService;
//
// @Mock
// private GSRepository gsRepository;
//
// @Test
// @DisplayName("비회원 일정 조회 시 잘못된 ID로 예외 발생")
// public void getGuestScheduleWhenInvalidId() {
// Long invalidId = 999L;
//
// // when
// doReturn(Optional.empty()).when(gsRepository).findById(invalidId);
//
// // then
// assertThatThrownBy(() -> gsService.getGuestSchedule(invalidId))
// .isInstanceOf(GSException.class)
// .hasMessage(SCHEDULE_NOT_FOUND.getMessage());
// }
//
// @Test
// @DisplayName("10일 이상 지난 PROGRESS 상태의 스케줄 disable 처리")
// public void disableProgressGuestSchedule() {
// LocalDateTime tenDaysAgo = LocalDateTime.now().minusDays(10);
//
// GuestSchedule progressSchedule = mock(GuestSchedule.class);
// lenient().when(progressSchedule.getStatus()).thenReturn(ScheduleStatus.PROGRESS);
// lenient().when(progressSchedule.getCreatedAt()).thenReturn(tenDaysAgo); // 10일 전으로 설정
//
// when(gsRepository.findByStatusAndCreatedAtBefore(eq(ScheduleStatus.PROGRESS), any()))
// .thenReturn(Collections.singletonList(progressSchedule));
//
// gsService.disableOldGuestSchedules();
//
// verify(progressSchedule).deactivate();
// }
//
// @Test
// @DisplayName("10일 이상 지난 COMPLETE 상태의 스케줄 disable 처리")
// public void disableCompleteGuestSchedule() {
// LocalDateTime tenDaysAgo = LocalDateTime.now().minusDays(10);
//
// GuestSchedule completeSchedule = mock(GuestSchedule.class);
// lenient().when(completeSchedule.getStatus()).thenReturn(ScheduleStatus.COMPLETE);
// lenient().when(completeSchedule.getUpdatedAt()).thenReturn(tenDaysAgo);
//
// when(gsRepository.findByStatusAndUpdatedAtBefore(eq(ScheduleStatus.COMPLETE), any()))
// .thenReturn(Collections.singletonList(completeSchedule));
//
// gsService.disableOldGuestSchedules();
//
// verify(completeSchedule).deactivate();
// }
//}