-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Ga Dong Sik <[email protected]>
- Loading branch information
Showing
9 changed files
with
279 additions
and
4 deletions.
There are no files selected for viewing
6 changes: 6 additions & 0 deletions
6
src/main/java/com/cozymate/cozymate_server/domain/chat/repository/ChatRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,13 @@ | ||
package com.cozymate.cozymate_server.domain.chat.repository; | ||
|
||
import com.cozymate.cozymate_server.domain.chat.Chat; | ||
import com.cozymate.cozymate_server.domain.chatroom.ChatRoom; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface ChatRepository extends JpaRepository<Chat, Long> { | ||
|
||
Optional<Chat> findTopByChatRoomOrderByIdDesc(ChatRoom chatRoom); | ||
|
||
void deleteAllByChatRoom(ChatRoom chatRoom); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
...main/java/com/cozymate/cozymate_server/domain/chatroom/controller/ChatRoomController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.cozymate.cozymate_server.domain.chatroom.controller; | ||
|
||
import com.cozymate.cozymate_server.domain.chatroom.service.ChatRoomCommandService; | ||
import com.cozymate.cozymate_server.global.response.ApiResponse; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/chatrooms") | ||
public class ChatRoomController { | ||
|
||
private final ChatRoomCommandService chatRoomCommandService; | ||
|
||
// TODO: 파라미터로 받는 myId는 추후 시큐리티 인증 객체에서 받아오는 것으로 변경 예정 | ||
@DeleteMapping("/{chatRoomId}") | ||
@Operation(summary = "[베로] 쪽지방 삭제 기능", description = "chatRoomId : 나갈 쪽지방 pk") | ||
public ResponseEntity<ApiResponse<String>> deleteChatRoom( | ||
@RequestParam Long myId, @PathVariable Long chatRoomId) { | ||
chatRoomCommandService.deleteChatRoom(myId, chatRoomId); | ||
return ResponseEntity.ok(ApiResponse.onSuccess("쪽지방 삭제 완료")); | ||
} | ||
} |
3 changes: 2 additions & 1 deletion
3
...r/domain/chatroom/ChatRoomRepository.java → ...atroom/repository/ChatRoomRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
...ain/java/com/cozymate/cozymate_server/domain/chatroom/service/ChatRoomCommandService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.cozymate.cozymate_server.domain.chatroom.service; | ||
|
||
import com.cozymate.cozymate_server.domain.chat.repository.ChatRepository; | ||
import com.cozymate.cozymate_server.domain.chatroom.ChatRoom; | ||
import com.cozymate.cozymate_server.domain.chatroom.repository.ChatRoomRepository; | ||
import com.cozymate.cozymate_server.global.response.code.status.ErrorStatus; | ||
import com.cozymate.cozymate_server.global.response.exception.GeneralException; | ||
import java.time.LocalDateTime; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@Transactional | ||
@RequiredArgsConstructor | ||
public class ChatRoomCommandService { | ||
|
||
private final ChatRoomRepository chatRoomRepository; | ||
private final ChatRepository chatRepository; | ||
|
||
public void deleteChatRoom(Long myId, Long chatRoomId) { | ||
ChatRoom chatRoom = chatRoomRepository.findById(chatRoomId) | ||
.orElseThrow(() -> new GeneralException(ErrorStatus._CHATROOM_NOT_FOUND)); | ||
|
||
softDeleteChatRoom(chatRoom, myId); | ||
|
||
tryHardDeleteChatRoom(chatRoom); | ||
} | ||
|
||
private void softDeleteChatRoom(ChatRoom chatRoom, Long myId) { | ||
if (chatRoom.getMemberA().getId().equals(myId)) { | ||
chatRoom.updateMemberALastDeleteAt(); | ||
} else if (chatRoom.getMemberB().getId().equals(myId)) { | ||
chatRoom.updateMemberBLastDeleteAt(); | ||
} else { | ||
throw new GeneralException(ErrorStatus._CHATROOM_FORBIDDEN); | ||
} | ||
} | ||
|
||
private void tryHardDeleteChatRoom(ChatRoom chatRoom) { | ||
LocalDateTime memberALastDeleteAt = chatRoom.getMemberALastDeleteAt(); | ||
LocalDateTime memberBLastDeleteAt = chatRoom.getMemberBLastDeleteAt(); | ||
|
||
if (memberALastDeleteAt != null && memberBLastDeleteAt != null && canHardDelete(chatRoom, | ||
memberALastDeleteAt, memberBLastDeleteAt)) { | ||
hardDeleteChatRoom(chatRoom); | ||
} | ||
} | ||
|
||
private boolean canHardDelete(ChatRoom chatRoom, LocalDateTime memberALastDeleteAt, | ||
LocalDateTime memberBLastDeleteAt) { | ||
return chatRepository.findTopByChatRoomOrderByIdDesc(chatRoom) | ||
.map(chat -> chat.getCreatedAt().isBefore(memberALastDeleteAt) && chat.getCreatedAt() | ||
.isBefore(memberBLastDeleteAt)) | ||
.orElse(false); | ||
} | ||
|
||
private void hardDeleteChatRoom(ChatRoom chatRoom) { | ||
chatRepository.deleteAllByChatRoom(chatRoom); | ||
chatRoomRepository.delete(chatRoom); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
166 changes: 166 additions & 0 deletions
166
...java/com/cozymate/cozymate_server/domain/chatroom/service/ChatRoomCommandServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package com.cozymate.cozymate_server.domain.chatroom.service; | ||
|
||
import static org.mockito.BDDMockito.given; | ||
import static org.mockito.Mockito.mock; | ||
|
||
import com.cozymate.cozymate_server.domain.chat.Chat; | ||
import com.cozymate.cozymate_server.domain.chat.repository.ChatRepository; | ||
import com.cozymate.cozymate_server.domain.chatroom.ChatRoom; | ||
import com.cozymate.cozymate_server.domain.chatroom.repository.ChatRoomRepository; | ||
import com.cozymate.cozymate_server.domain.chatroom.ChatRoomTestBuilder; | ||
import com.cozymate.cozymate_server.global.response.exception.GeneralException; | ||
import java.time.LocalDateTime; | ||
import java.util.Optional; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.DisplayNameGeneration; | ||
import org.junit.jupiter.api.DisplayNameGenerator; | ||
import org.junit.jupiter.api.Nested; | ||
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 static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.BDDMockito.*; | ||
|
||
@ExtendWith(MockitoExtension.class) | ||
@DisplayName("ChatRoomCommandService 클래스의") | ||
public class ChatRoomCommandServiceTest { | ||
@Mock | ||
ChatRoomRepository chatRoomRepository; | ||
@Mock | ||
ChatRepository chatRepository; | ||
@InjectMocks | ||
ChatRoomCommandService chatRoomCommandService; | ||
ChatRoom chatRoom; | ||
Chat chat; | ||
LocalDateTime methodStartTime; | ||
|
||
@Nested | ||
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) | ||
class deleteChatRoom_메서드는 { | ||
|
||
@Nested | ||
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) | ||
class 쪽지방을_한명만_삭제한_경우 { | ||
|
||
@BeforeEach | ||
void setUp() { | ||
chatRoom = ChatRoomTestBuilder.testChatRoomBuild(); | ||
chat = mock(Chat.class); | ||
methodStartTime = LocalDateTime.now(); | ||
|
||
given(chatRoomRepository.findById(chatRoom.getId())).willReturn( | ||
Optional.of(chatRoom)); | ||
} | ||
|
||
@Test | ||
@DisplayName("ChatRoom의 deleteAt필드에 삭제 시간을 업데이트하여 논리적으로 삭제한다.") | ||
void it_returns_update_deleteAt_soft_delete() { | ||
chatRoomCommandService.deleteChatRoom(chatRoom.getMemberA().getId(), chatRoom.getId()); | ||
LocalDateTime memberALastDeleteAt = chatRoom.getMemberALastDeleteAt(); | ||
assertThat(memberALastDeleteAt).isAfter(methodStartTime); | ||
assertThat(chatRoom.getMemberBLastDeleteAt()).isNull(); | ||
} | ||
} | ||
|
||
@Nested | ||
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) | ||
class 쪽지방을_두명_다_삭제한_경우 { | ||
|
||
@Nested | ||
@DisplayName("둘의 deleteAt 시간 보다 가장 최신 Chat의 createdAt이 빠른 경우") | ||
class Context_with_chat_createAt_earlier_than_two_member_deleteAt { | ||
|
||
@BeforeEach | ||
void setUp() { | ||
chatRoom = ChatRoomTestBuilder.testChatRoomBuild(); | ||
chat = mock(Chat.class); | ||
chatRoom.updateMemberBLastDeleteAt(); | ||
|
||
given(chatRoomRepository.findById(chatRoom.getId())).willReturn( | ||
Optional.of(chatRoom)); | ||
given(chatRepository.findTopByChatRoomOrderByIdDesc(chatRoom)).willReturn( | ||
Optional.of(chat)); | ||
given(chat.getCreatedAt()).willReturn(LocalDateTime.now().minusDays(1)); | ||
doNothing().when(chatRepository).deleteAllByChatRoom(chatRoom); | ||
doNothing().when(chatRoomRepository).delete(chatRoom); | ||
} | ||
|
||
@Test | ||
@DisplayName("해당 쪽지방과 쪽지방의 쪽지를 물리적으로 DB에서 삭제한다.") | ||
void it_returns_physically_delete() { | ||
chatRoomCommandService.deleteChatRoom(chatRoom.getMemberA().getId(), chatRoom.getId()); | ||
then(chatRepository).should(timeout(1)).deleteAllByChatRoom(chatRoom); | ||
then(chatRoomRepository).should(timeout(1)).delete(chatRoom); | ||
} | ||
} | ||
|
||
@Nested | ||
@DisplayName("가장 최신 쪽지 생성일이 두 명의 deleteAt 중에서 적어도 하나 보다 최근인 경우") | ||
class Context_with_chat_createdAt_later_than_any_deleteAt { | ||
|
||
@BeforeEach | ||
void setUp() { | ||
chatRoom = ChatRoomTestBuilder.testChatRoomBuild(); | ||
chat = mock(Chat.class); | ||
chatRoom.updateMemberBLastDeleteAt(); | ||
methodStartTime = LocalDateTime.now(); | ||
|
||
given(chatRoomRepository.findById(chatRoom.getId())).willReturn( | ||
Optional.of(chatRoom)); | ||
given(chatRepository.findTopByChatRoomOrderByIdDesc(chatRoom)).willReturn( | ||
Optional.of(chat)); | ||
given(chat.getCreatedAt()).willReturn(LocalDateTime.now().plusDays(1)); | ||
} | ||
|
||
@Test | ||
@DisplayName("ChatRoom의 deleteAt필드에 삭제 시간을 업데이트하여 논리적으로 삭제한다.") | ||
void it_returns_update_deleteAt_soft_delete() { | ||
chatRoomCommandService.deleteChatRoom(chatRoom.getMemberA().getId(), chatRoom.getId()); | ||
LocalDateTime memberALastDeleteAt = chatRoom.getMemberALastDeleteAt(); | ||
assertThat(memberALastDeleteAt).isAfter(methodStartTime); | ||
} | ||
} | ||
} | ||
|
||
@Nested | ||
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) | ||
class 유효하지_않은_chatRoomId인_경우 { | ||
|
||
@BeforeEach | ||
void setUp() { | ||
given(chatRoomRepository.findById(1L)).willReturn(Optional.empty()); | ||
} | ||
|
||
@Test | ||
@DisplayName("예외를 발생시킨다.") | ||
void it_returns_not_found_chat_room_exception() { | ||
assertThatThrownBy(() -> chatRoomCommandService.deleteChatRoom(1L, 1L)) | ||
.isInstanceOf(GeneralException.class); | ||
} | ||
} | ||
|
||
@Nested | ||
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) | ||
class myId가_해당_쪽지방의_멤버가_아닌_경우 { | ||
|
||
@BeforeEach | ||
void setUp() { | ||
chatRoom = ChatRoomTestBuilder.testChatRoomBuild(); | ||
given(chatRoomRepository.findById(chatRoom.getId())).willReturn( | ||
Optional.of(chatRoom)); | ||
} | ||
|
||
@Test | ||
@DisplayName("예외를 발생시킨다.") | ||
void it_returns_chat_room_forbidden() { | ||
assertThatThrownBy(() -> chatRoomCommandService.deleteChatRoom(3L, chatRoom.getId())) | ||
.isInstanceOf(GeneralException.class); | ||
} | ||
} | ||
} | ||
} |