From 96b54d06bad8ba30e790941d1c1f3e703bf577d9 Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 00:20:45 +0900 Subject: [PATCH 01/29] =?UTF-8?q?feat:=20=EC=9D=BD=EC=9D=80=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EB=A1=9C=EA=B7=B8=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/chat/domain/ReadMessageLog.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java new file mode 100644 index 000000000..f330b8fff --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java @@ -0,0 +1,41 @@ +package com.ddang.ddang.chat.domain; + +import com.ddang.ddang.user.domain.User; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ForeignKey; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@EqualsAndHashCode(of = "id", callSuper = false) +@ToString(of = "id") +public class ReadMessageLog { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "chat_room_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_chat_room")) + private ChatRoom chatRoom; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "auction_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_reader")) + private User reader; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "message_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_message")) + private Message message; +} From aabc0ef96e6507bebd06f44a57be848903be1274 Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 01:40:04 +0900 Subject: [PATCH 02/29] =?UTF-8?q?feat:=20=EC=9D=BD=EC=9D=80=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EB=A1=9C=EA=B7=B8=20=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?=EB=A0=88=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ReadMessageLogRepository.java | 12 ++ .../JpaReadMessageLogRepository.java | 17 +++ .../ReadMessageLogRepositoryImpl.java | 25 ++++ .../persistence/JpaMessageRepositoryTest.java | 2 - .../ReadMessageLogRepositoryImplTest.java | 48 ++++++++ .../ReadMessageLogRepositoryFixture.java | 116 ++++++++++++++++++ 6 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaReadMessageLogRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java new file mode 100644 index 000000000..1e254efdd --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java @@ -0,0 +1,12 @@ +package com.ddang.ddang.chat.domain.repository; + +import com.ddang.ddang.chat.domain.ReadMessageLog; + +import java.util.Optional; + +public interface ReadMessageLogRepository { + + ReadMessageLog save(final ReadMessageLog readMessageLog); + + Optional findLastReadMessageBy(final Long readerId, final Long chatRoomId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaReadMessageLogRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaReadMessageLogRepository.java new file mode 100644 index 000000000..51a5150f9 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaReadMessageLogRepository.java @@ -0,0 +1,17 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.ReadMessageLog; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.Optional; + +public interface JpaReadMessageLogRepository extends JpaRepository { + + @Query(""" + SELECT rml.id + FROM ReadMessageLog rml + WHERE rml.chatRoom.id = :chatRoomId AND rml.reader.id = :readerId + """) + Optional findLastReadMessageByUserIdAndChatRoomId(final Long readerId, final Long chatRoomId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java new file mode 100644 index 000000000..77a3eeb00 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java @@ -0,0 +1,25 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.ReadMessageLog; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class ReadMessageLogRepositoryImpl implements ReadMessageLogRepository { + + private final JpaReadMessageLogRepository jpaReadMessageLogRepository; + + @Override + public ReadMessageLog save(final ReadMessageLog readMessageLog) { + return jpaReadMessageLogRepository.save(readMessageLog); + } + + @Override + public Optional findLastReadMessageBy(final Long readerId, final Long chatRoomId) { + return jpaReadMessageLogRepository.findLastReadMessageByUserIdAndChatRoomId(readerId, chatRoomId); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepositoryTest.java index 0cb97b3e3..c12aa23f4 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepositoryTest.java @@ -4,8 +4,6 @@ import com.ddang.ddang.chat.infrastructure.persistence.fixture.JpaMessageRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java new file mode 100644 index 000000000..549ceda1b --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java @@ -0,0 +1,48 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.ReadMessageLog; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; +import com.ddang.ddang.chat.infrastructure.persistence.fixture.ReadMessageLogRepositoryFixture; +import com.ddang.ddang.configuration.JpaConfiguration; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class ReadMessageLogRepositoryImplTest extends ReadMessageLogRepositoryFixture { + + @Autowired + ReadMessageLogRepository readMessageLogRepository; + + @Test + void 마지막_읽은_메시지를_저장한다() { + // given + final ReadMessageLog actual = readMessageLogRepository.save(다섯_번째_메시지까지_읽은_메시지_로그); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 메시지_조회자_아이디와_채팅방_아이디에_해당하는_마지막_메시지를_반환한다() { + // given + final Optional actual = readMessageLogRepository.findLastReadMessageBy(메리.getId(), 메리_엔초_채팅방.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).isPresent(); + softAssertions.assertThat(actual.get().getLastReadMessage().getId()).isEqualTo(다섯_번째_메시지.getId()); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java new file mode 100644 index 000000000..5766113f9 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java @@ -0,0 +1,116 @@ +package com.ddang.ddang.chat.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.domain.repository.BidRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.chat.domain.ReadMessageLog; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.MessageRepository; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +public class ReadMessageLogRepositoryFixture { + + @Autowired + private AuctionRepository auctionRepository; + + @Autowired + private JpaCategoryRepository categoryRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private BidRepository bidRepository; + + @Autowired + private ChatRoomRepository chatRoomRepository; + + @Autowired + private MessageRepository messageRepository; + + protected ChatRoom 메리_엔초_채팅방; + protected User 메리; + protected User 엔초; + protected ReadMessageLog 다섯_번째_메시지까지_읽은_메시지_로그; + protected Message 다섯_번째_메시지; + + protected AuctionImage 메리의_경매_대표_이미지 = new AuctionImage("메리_경매_대표_이미지.png", "메리의_경매_대표_이미지.png"); + protected AuctionImage 메리의_대표_이미지가_아닌_경매_이미지 = new AuctionImage("메리의_대표 이미지가_아닌_경매_이미지.png", "메리의_대표 이미지가_아닌_경매_이미지.png"); + protected ProfileImage 프로필_이미지 = new ProfileImage("upload.png", "store.png"); + + @BeforeEach + void setUp() { + final Category 전자기기_카테고리 = new Category("전자기기"); + final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); + categoryRepository.save(전자기기_카테고리); + + 메리 = User.builder() + .name("메리_판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 엔초 = User.builder() + .name("엔초_구매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("14567") + .build(); + userRepository.save(메리); + userRepository.save(엔초); + + final Auction 판매자_메리_구매자_엔초_경매 = Auction.builder() + .seller(메리) + .title("메리 맥북") + .description("메리 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 판매자_메리_구매자_엔초_경매.addAuctionImages(List.of(메리의_경매_대표_이미지, 메리의_대표_이미지가_아닌_경매_이미지)); + auctionRepository.save(판매자_메리_구매자_엔초_경매); + + + final Bid 엔초가_메리_경매에_입찰 = new Bid(판매자_메리_구매자_엔초_경매, 엔초, new BidPrice(15_000)); + bidRepository.save(엔초가_메리_경매에_입찰); + + 판매자_메리_구매자_엔초_경매.updateLastBid(엔초가_메리_경매에_입찰); + 메리_엔초_채팅방 = new ChatRoom(판매자_메리_구매자_엔초_경매, 엔초); + chatRoomRepository.save(메리_엔초_채팅방); + + List 메리_엔초_메시지들 = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + final Message 메시지 = Message.builder() + .chatRoom(메리_엔초_채팅방) + .writer(메리) + .receiver(엔초) + .contents("안녕하세요") + .build(); + messageRepository.save(메시지); + 메리_엔초_메시지들.add(메시지); + } + + 다섯_번째_메시지 = 메리_엔초_메시지들.get(4); + 다섯_번째_메시지까지_읽은_메시지_로그 = new ReadMessageLog(메리_엔초_채팅방, 메리, 다섯_번째_메시지); + } +} From de9e5e9b00b094215ccac74da794e27205ac2ec4 Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 01:42:00 +0900 Subject: [PATCH 03/29] =?UTF-8?q?refactor:=20=EC=BB=AC=EB=9F=BC=EB=AA=85?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/ddang/chat/domain/ReadMessageLog.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java index f330b8fff..83f2928df 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java @@ -32,10 +32,20 @@ public class ReadMessageLog { private ChatRoom chatRoom; @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "auction_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_reader")) + @JoinColumn(name = "reader_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_reader")) private User reader; @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "message_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_message")) - private Message message; + @JoinColumn(name = "last_message_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_last_read_message")) + private Message lastReadMessage; + + public ReadMessageLog(final ChatRoom chatRoom, final User reader, final Message lastReadMessage) { + this.chatRoom = chatRoom; + this.reader = reader; + this.lastReadMessage = lastReadMessage; + } + + public void updateLastReadMessage(final Message lastReadMessage) { + this.lastReadMessage = lastReadMessage; + } } From c77302398c710633c9fe6ffa71fc6927728b125a Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 02:18:56 +0900 Subject: [PATCH 04/29] =?UTF-8?q?feat:=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EB=A7=88=EC=A7=80=EB=A7=89?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=BD=EC=9D=80=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=20=EB=A1=9C=EA=B7=B8=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/application/MessageService.java | 22 +++++++++++++++---- .../ddang/chat/domain/ReadMessageLog.java | 16 ++++++-------- .../JpaReadMessageLogRepository.java | 2 +- .../chat/application/MessageServiceTest.java | 16 ++++++++++++++ .../fixture/MessageServiceFixture.java | 22 ++++++++++++++++++- 5 files changed, 63 insertions(+), 15 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index 35493d0f5..e6239353f 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -5,11 +5,14 @@ import com.ddang.ddang.chat.application.event.MessageNotificationEvent; import com.ddang.ddang.chat.application.exception.ChatRoomNotFoundException; import com.ddang.ddang.chat.application.exception.MessageNotFoundException; +import com.ddang.ddang.chat.application.exception.ReadMessageLogNotFoundException; import com.ddang.ddang.chat.application.exception.UnableToChatException; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.chat.domain.ReadMessageLog; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.chat.domain.repository.MessageRepository; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.chat.presentation.dto.request.ReadMessageRequest; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; @@ -30,6 +33,7 @@ public class MessageService { private final ApplicationEventPublisher messageEventPublisher; private final MessageRepository messageRepository; + private final ReadMessageLogRepository readMessageLogRepository; private final ChatRoomRepository chatRoomRepository; private final UserRepository userRepository; @@ -58,11 +62,10 @@ public Long create(final CreateMessageDto dto, final String profileImageAbsolute return persistMessage.getId(); } + @Transactional public List readAllByLastMessageId(final ReadMessageRequest request) { - if (!userRepository.existsById(request.messageReaderId())) { - throw new UserNotFoundException("지정한 아이디에 대한 사용자를 찾을 수 없습니다."); - } - + final User reader = userRepository.findById(request.messageReaderId()) + .orElseThrow(() -> new UserNotFoundException("지정한 아이디에 대한 사용자를 찾을 수 없습니다.")); final ChatRoom chatRoom = chatRoomRepository.findById(request.chatRoomId()) .orElseThrow(() -> new ChatRoomNotFoundException( "지정한 아이디에 대한 채팅방을 찾을 수 없습니다.")); @@ -77,11 +80,22 @@ public List readAllByLastMessageId(final ReadMessageRequest requ request.lastMessageId() ); + final Message lastReadMessage = readMessages.get(readMessages.size() - 1); + updateLastReadMessage(reader, chatRoom, lastReadMessage); + return readMessages.stream() .map(message -> ReadMessageDto.from(message, chatRoom)) .toList(); } + private void updateLastReadMessage(final User reader, final ChatRoom chatRoom, final Message lastReadMessage) { + final ReadMessageLog messageLog = readMessageLogRepository.findBy(reader.getId(), chatRoom.getId()) + .orElseThrow(() -> new ReadMessageLogNotFoundException( + "메시지 조회 로그가 존재하지 않습니다." + )); + messageLog.updateLastReadMessage(lastReadMessage.getId()); + } + private void validateLastMessageId(final Long lastMessageId) { if (!messageRepository.existsById(lastMessageId)) { throw new MessageNotFoundException("조회한 마지막 메시지가 존재하지 않습니다."); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java index 83f2928df..f1dd831bc 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java @@ -1,6 +1,7 @@ package com.ddang.ddang.chat.domain; import com.ddang.ddang.user.domain.User; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.ForeignKey; @@ -20,7 +21,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter @EqualsAndHashCode(of = "id", callSuper = false) -@ToString(of = "id") +@ToString(of = {"id", "lastReadMessageId"}) public class ReadMessageLog { @Id @@ -31,21 +32,18 @@ public class ReadMessageLog { @JoinColumn(name = "chat_room_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_chat_room")) private ChatRoom chatRoom; - @OneToOne(fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.REMOVE}) @JoinColumn(name = "reader_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_reader")) private User reader; - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "last_message_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_last_read_message")) - private Message lastReadMessage; + private Long lastReadMessageId = 0L; - public ReadMessageLog(final ChatRoom chatRoom, final User reader, final Message lastReadMessage) { + public ReadMessageLog(final ChatRoom chatRoom, final User reader) { this.chatRoom = chatRoom; this.reader = reader; - this.lastReadMessage = lastReadMessage; } - public void updateLastReadMessage(final Message lastReadMessage) { - this.lastReadMessage = lastReadMessage; + public void updateLastReadMessage(final Long lastReadMessageId) { + this.lastReadMessageId = lastReadMessageId; } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaReadMessageLogRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaReadMessageLogRepository.java index 51a5150f9..8ceceeb93 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaReadMessageLogRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaReadMessageLogRepository.java @@ -9,7 +9,7 @@ public interface JpaReadMessageLogRepository extends JpaRepository { @Query(""" - SELECT rml.id + SELECT rml FROM ReadMessageLog rml WHERE rml.chatRoom.id = :chatRoomId AND rml.reader.id = :readerId """) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/MessageServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/MessageServiceTest.java index a65cadb92..b313b22b7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/MessageServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/MessageServiceTest.java @@ -5,6 +5,8 @@ import com.ddang.ddang.chat.application.exception.ChatRoomNotFoundException; import com.ddang.ddang.chat.application.exception.MessageNotFoundException; import com.ddang.ddang.chat.application.fixture.MessageServiceFixture; +import com.ddang.ddang.chat.domain.ReadMessageLog; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.notification.application.NotificationService; import com.ddang.ddang.notification.application.dto.CreateNotificationDto; @@ -20,6 +22,7 @@ import org.springframework.test.context.event.RecordApplicationEvents; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -35,6 +38,9 @@ class MessageServiceTest extends MessageServiceFixture { @Autowired MessageService messageService; + @Autowired + ReadMessageLogRepository readMessageLogRepository; + @MockBean NotificationService notificationService; @@ -126,6 +132,16 @@ class MessageServiceTest extends MessageServiceFixture { assertThat(readMessageDtos).isEmpty(); } + @Test + void 메시지를_조회할_경우_마지막으로_읽은_메시지가_업데이트된다() { + // when + messageService.readAllByLastMessageId(조회한_마지막_메시지가_5인_메시지_조회용_request); + final Optional readMessageLog = readMessageLogRepository.findBy(발신자.getId(), 메시지가_5개인_채팅방.getId()); + + // then + assertThat(readMessageLog.get().getLastReadMessageId()).isEqualTo(메시지가_5개인_채팅방_메시지의_마지막_메시지); + } + @Test void 잘못된_사용자가_메시지를_조회할_경우_예외가_발생한다() { // when & then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java index 892695e39..bd7af5daf 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java @@ -49,9 +49,13 @@ public class MessageServiceFixture { protected ReadMessageRequest 마지막_조회_메시지_아이디가_없는_메시지_조회용_request; protected ReadMessageRequest 두_번째_메시지부터_모든_메시지_조회용_request; protected ReadMessageRequest 조회할_메시지가_더이상_없는_메시지_조회용_request; + protected ReadMessageRequest 조회한_마지막_메시지가_5인_메시지_조회용_request; protected ReadMessageRequest 유효하지_않은_사용자의_메시지_조회용_request; protected ReadMessageRequest 유효하지_않은_채팅방의_메시지_조회용_request; protected ReadMessageRequest 존재하지_않는_마지막_메시지_아이디의_메시지_조회용_request; + protected User 발신자; + protected ChatRoom 메시지가_5개인_채팅방; + protected Message 메시지가_5개인_채팅방_메시지의_마지막_메시지; protected String 이미지_절대_경로 = "/imageUrl"; protected int 메시지_총_개수 = 10; @@ -72,7 +76,7 @@ void setUp() { .build(); auctionRepository.save(경매); - final User 발신자 = User.builder() + 발신자 = User.builder() .name("발신자") .profileImage(new ProfileImage("upload.png", "store.png")) .reliability(new Reliability(4.7d)) @@ -97,9 +101,11 @@ void setUp() { final ChatRoom 채팅방 = new ChatRoom(경매, 발신자); final ChatRoom 탈퇴한_사용자와의_채팅방 = new ChatRoom(경매, 탈퇴한_사용자); + 메시지가_5개인_채팅방 = new ChatRoom(경매, 발신자); chatRoomRepository.save(채팅방); chatRoomRepository.save(탈퇴한_사용자와의_채팅방); + chatRoomRepository.save(메시지가_5개인_채팅방); 메시지_생성_DTO = new CreateMessageDto( 채팅방.getId(), @@ -144,6 +150,19 @@ void setUp() { messageRepository.save(메시지); } + final List 메시지가_5개인_채팅방_메시지들 = new ArrayList<>(); + for (int count = 0; count < 5; count++) { + final Message 메시지 = Message.builder() + .writer(발신자) + .receiver(수신자) + .chatRoom(메시지가_5개인_채팅방) + .contents("메시지 내용") + .build(); + 메시지가_5개인_채팅방_메시지들.add(메시지); + messageRepository.save(메시지); + } + 메시지가_5개인_채팅방_메시지의_마지막_메시지 = 메시지가_5개인_채팅방_메시지들.get(4); + 마지막_조회_메시지_아이디가_없는_메시지_조회용_request = new ReadMessageRequest(발신자.getId(), 채팅방.getId(), null); 두_번째_메시지부터_모든_메시지_조회용_request = new ReadMessageRequest(발신자.getId(), 채팅방.getId(), 메시지들.get(0).getId()); 조회할_메시지가_더이상_없는_메시지_조회용_request = new ReadMessageRequest(발신자.getId(), 채팅방.getId(), 메시지들.get(메시지_총_개수 - 1) @@ -151,5 +170,6 @@ void setUp() { 유효하지_않은_사용자의_메시지_조회용_request = new ReadMessageRequest(-999L, 채팅방.getId(), null); 유효하지_않은_채팅방의_메시지_조회용_request = new ReadMessageRequest(발신자.getId(), -999L, null); 존재하지_않는_마지막_메시지_아이디의_메시지_조회용_request = new ReadMessageRequest(발신자.getId(), 채팅방.getId(), -999L); + 조회한_마지막_메시지가_5인_메시지_조회용_request = new ReadMessageRequest(발신자.getId(), 메시지가_5개인_채팅방.getId(), null); } } From ce34598ca2802f7a2571c143a3305ef4478ad08b Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 19:40:35 +0900 Subject: [PATCH 05/29] =?UTF-8?q?feat:=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EC=9D=BD?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EA=B0=9C=EC=88=98=EB=A5=BC=20=ED=8F=AC=ED=95=A8=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/ChatRoomAndMessageAndImageDto.java | 7 +- ...lChatRoomAndMessageAndImageRepository.java | 25 ++- ...mAndMessageAndImageQueryProjectionDto.java | 10 +- ...tRoomAndMessageAndImageRepositoryTest.java | 43 ++++- ...omAndMessageAndImageRepositoryFixture.java | 167 +++++++++++------- 5 files changed, 175 insertions(+), 77 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndMessageAndImageDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndMessageAndImageDto.java index 2e7e6ea6b..b31168c91 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndMessageAndImageDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndMessageAndImageDto.java @@ -4,5 +4,10 @@ import com.ddang.ddang.chat.domain.Message; import com.ddang.ddang.image.domain.AuctionImage; -public record ChatRoomAndMessageAndImageDto(ChatRoom chatRoom, Message message, AuctionImage thumbnailImage) { +public record ChatRoomAndMessageAndImageDto( + ChatRoom chatRoom, + Message message, + AuctionImage thumbnailImage, + Long unreadMessageCount +) { } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepository.java index 07e7bc5f7..26734527e 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepository.java @@ -5,6 +5,7 @@ import com.ddang.ddang.chat.infrastructure.persistence.dto.QChatRoomAndMessageAndImageQueryProjectionDto; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.JPQLQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -15,6 +16,7 @@ import static com.ddang.ddang.auction.domain.QAuction.auction; import static com.ddang.ddang.chat.domain.QChatRoom.chatRoom; import static com.ddang.ddang.chat.domain.QMessage.message; +import static com.ddang.ddang.chat.domain.QReadMessageLog.readMessageLog; import static com.ddang.ddang.image.domain.QAuctionImage.auctionImage; import static java.util.Comparator.comparing; @@ -26,8 +28,12 @@ public class QuerydslChatRoomAndMessageAndImageRepository { public List findAllChatRoomInfoByUserIdOrderByLastMessage(final Long userId) { final List unsortedDtos = - queryFactory.select(new QChatRoomAndMessageAndImageQueryProjectionDto(chatRoom, message, auctionImage)) - .from(chatRoom) + queryFactory.select(new QChatRoomAndMessageAndImageQueryProjectionDto( + chatRoom, + message, + auctionImage, + countUnreadMessages(userId) + )).from(chatRoom) .leftJoin(chatRoom.buyer).fetchJoin() .leftJoin(chatRoom.auction, auction).fetchJoin() .leftJoin(auction.seller).fetchJoin() @@ -52,6 +58,21 @@ public List findAllChatRoomInfoByUserIdOrderByLas return sortByLastMessageIdDesc(unsortedDtos); } + private static JPQLQuery countUnreadMessages(final Long userId) { + return JPAExpressions.select(message.count()) + .from(message) + .where( + message.chatRoom.id.eq(chatRoom.id), + message.writer.id.ne(userId), + message.id.gt( + JPAExpressions + .select(readMessageLog.lastReadMessageId) + .from(readMessageLog) + .where(readMessageLog.reader.id.eq(userId)) + ) + ); + } + private List sortByLastMessageIdDesc( final List unsortedDtos ) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java index c4369d8f3..f4a2b49a3 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java @@ -6,7 +6,12 @@ import com.ddang.ddang.image.domain.AuctionImage; import com.querydsl.core.annotations.QueryProjection; -public record ChatRoomAndMessageAndImageQueryProjectionDto(ChatRoom chatRoom, Message message, AuctionImage auctionImage) { +public record ChatRoomAndMessageAndImageQueryProjectionDto( + ChatRoom chatRoom, + Message message, + AuctionImage auctionImage, + Long unreadMessage +) { @QueryProjection public ChatRoomAndMessageAndImageQueryProjectionDto { @@ -16,7 +21,8 @@ public ChatRoomAndMessageAndImageDto toSortedDto() { return new ChatRoomAndMessageAndImageDto( this.chatRoom, this.message, - this.auctionImage + this.auctionImage, + this.unreadMessage ); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java index 694cb6999..89ead8823 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java @@ -1,6 +1,9 @@ package com.ddang.ddang.chat.infrastructure.persistence; +import com.ddang.ddang.chat.domain.ReadMessageLog; import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; +import com.ddang.ddang.chat.domain.repository.MessageRepository; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.chat.infrastructure.persistence.fixture.QuerydslChatRoomAndMessageAndImageRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; @@ -24,9 +27,42 @@ class QuerydslChatRoomAndMessageAndImageRepositoryTest extends QuerydslChatRoomA QuerydslChatRoomAndMessageAndImageRepository querydslChatRoomAndMessageAndImageRepository; + ReadMessageLogRepository readMessageLogRepository; + + MessageRepository messageRepository; + @BeforeEach - void setUp(@Autowired final JPAQueryFactory queryFactory) { + void setUp( + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaReadMessageLogRepository jpaReadMessageLogRepository, + @Autowired final JpaMessageRepository jpaMessageRepository + ) { querydslChatRoomAndMessageAndImageRepository = new QuerydslChatRoomAndMessageAndImageRepository(queryFactory); + readMessageLogRepository = new ReadMessageLogRepositoryImpl(jpaReadMessageLogRepository); + messageRepository = new MessageRepositoryImpl(jpaMessageRepository, new QuerydslMessageRepository(queryFactory)); + } + + @Test + void 사용자가_읽지_않은_메시지_개수를_반환한다() { + // given + readMessageLogRepository.save(new ReadMessageLog(메리_엔초_채팅방, 엔초)); + readMessageLogRepository.save(new ReadMessageLog(메리_엔초_채팅방, 메리)); + + // when + messageRepository.save(메리가_엔초에게_3시에_보낸_쪽지1); + messageRepository.save(메리가_엔초에게_3시에_보낸_쪽지2); + messageRepository.save(메리가_엔초에게_3시에_보낸_쪽지3); + messageRepository.save(엔초가_메리에게_3시에_보낸_쪽지); + final List actual_엔초 = querydslChatRoomAndMessageAndImageRepository + .findAllChatRoomInfoByUserIdOrderByLastMessage(엔초.getId()); + final List actual_메리 = querydslChatRoomAndMessageAndImageRepository + .findAllChatRoomInfoByUserIdOrderByLastMessage(메리.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual_엔초.get(0).unreadMessageCount()).isEqualTo(3); + softAssertions.assertThat(actual_메리.get(0).unreadMessageCount()).isEqualTo(1); + }); } @Test @@ -37,16 +73,13 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { // then SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual).hasSize(3); + softAssertions.assertThat(actual).hasSize(2); softAssertions.assertThat(actual.get(0).chatRoom()).isEqualTo(엔초_지토_채팅방); softAssertions.assertThat(actual.get(0).message()).isEqualTo(엔초가_지토에게_5시에_보낸_쪽지); softAssertions.assertThat(actual.get(0).thumbnailImage()).isEqualTo(엔초의_경매_대표_이미지); softAssertions.assertThat(actual.get(1).chatRoom()).isEqualTo(제이미_엔초_채팅방); softAssertions.assertThat(actual.get(1).message()).isEqualTo(제이미가_엔초에게_4시에_보낸_쪽지); softAssertions.assertThat(actual.get(1).thumbnailImage()).isEqualTo(제이미의_경매_대표_이미지); - softAssertions.assertThat(actual.get(2).chatRoom()).isEqualTo(메리_엔초_채팅방); - softAssertions.assertThat(actual.get(2).message()).isEqualTo(메리가_엔초에게_3시에_보낸_쪽지); - softAssertions.assertThat(actual.get(2).thumbnailImage()).isEqualTo(메리의_경매_대표_이미지); }); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryFixture.java index 49bdf7e18..357cbf052 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryFixture.java @@ -58,15 +58,20 @@ public class QuerydslChatRoomAndMessageAndImageRepositoryFixture { private JpaMessageRepository messageRepository; protected User 엔초; + protected User 메리; protected AuctionImage 메리의_경매_대표_이미지; protected AuctionImage 엔초의_경매_대표_이미지; protected AuctionImage 제이미의_경매_대표_이미지; protected ChatRoom 메리_엔초_채팅방; protected ChatRoom 엔초_지토_채팅방; protected ChatRoom 제이미_엔초_채팅방; - protected Message 메리가_엔초에게_3시에_보낸_쪽지; protected Message 제이미가_엔초에게_4시에_보낸_쪽지; protected Message 엔초가_지토에게_5시에_보낸_쪽지; + protected Message 엔초가_지토에게_추가로_보낸_쪽지; + protected Message 메리가_엔초에게_3시에_보낸_쪽지1; + protected Message 메리가_엔초에게_3시에_보낸_쪽지2; + protected Message 메리가_엔초에게_3시에_보낸_쪽지3; + protected Message 엔초가_메리에게_3시에_보낸_쪽지; @BeforeEach void setUp() { @@ -80,24 +85,24 @@ void setUp() { .reliability(new Reliability(4.7d)) .oauthId("12346") .build(); - final User 메리 = User.builder() - .name("메리") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); + 메리 = User.builder() + .name("메리") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); final User 제이미 = User.builder() - .name("제이미") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12347") - .build(); - final User 지토 = User.builder() - .name("지토") + .name("제이미") .profileImage(프로필_이미지) .reliability(new Reliability(4.7d)) - .oauthId("12348") + .oauthId("12347") .build(); + final User 지토 = User.builder() + .name("지토") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12348") + .build(); 메리의_경매_대표_이미지 = new AuctionImage("메리의_경매_대표_이미지.png", "메리의_경매_대표_이미지.png"); final AuctionImage 메리의_대표_이미지가_아닌_경매_이미지 = @@ -110,32 +115,32 @@ void setUp() { new AuctionImage("제이미의_대표 이미지가_아닌_경매_이미지.png", "제이미의_대표 이미지가_아닌_경매_이미지.png"); final Auction 메리의_경매 = Auction.builder() - .seller(메리) - .title("메리 맥북") - .description("메리 맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(메리) + .title("메리 맥북") + .description("메리 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); final Auction 엔초의_경매 = Auction.builder() - .seller(엔초) - .title("엔초 맥북") - .description("엔초 맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(엔초) + .title("엔초 맥북") + .description("엔초 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); final Auction 제이미의_경매 = Auction.builder() - .seller(제이미) - .title("제이미 맥북") - .description("제이미 맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(제이미) + .title("제이미 맥북") + .description("제이미 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); final Bid 엔초가_메리_경매에_입찰 = new Bid(메리의_경매, 엔초, new BidPrice(15_000)); final Bid 지토가_엔초_경매에_입찰 = new Bid(엔초의_경매, 지토, new BidPrice(15_000)); @@ -146,36 +151,65 @@ void setUp() { 제이미_엔초_채팅방 = new ChatRoom(제이미의_경매, 엔초); final Message 제이미가_엔초에게_1시에_보낸_쪽지 = Message.builder() - .chatRoom(제이미_엔초_채팅방) - .contents("제이미가 엔초에게 1시애 보낸 쪽지") - .writer(제이미) - .receiver(엔초) - .build(); + .chatRoom(제이미_엔초_채팅방) + .contents("제이미가 엔초에게 1시애 보낸 쪽지") + .writer(제이미) + .receiver(엔초) + .build(); final Message 엔초가_지토에게_2시에_보낸_쪽지 = Message.builder() - .chatRoom(엔초_지토_채팅방) - .contents("엔초가 지토에게 2시애 보낸 쪽지") - .writer(엔초) - .receiver(지토) - .build(); - 메리가_엔초에게_3시에_보낸_쪽지 = Message.builder() - .chatRoom(메리_엔초_채팅방) - .contents("메리가 엔초에게 3시에 보낸 쪽지") - .writer(엔초) - .receiver(지토) - .build(); + .chatRoom(엔초_지토_채팅방) + .contents("엔초가 지토에게 2시애 보낸 쪽지") + .writer(엔초) + .receiver(지토) + .build(); 제이미가_엔초에게_4시에_보낸_쪽지 = Message.builder() - .chatRoom(제이미_엔초_채팅방) - .contents("제이미가 엔초에게 4시애 보낸 쪽지") - .writer(제이미) - .receiver(엔초) - .build(); + .chatRoom(제이미_엔초_채팅방) + .contents("제이미가 엔초에게 4시애 보낸 쪽지") + .writer(제이미) + .receiver(엔초) + .build(); 엔초가_지토에게_5시에_보낸_쪽지 = Message.builder() - .chatRoom(엔초_지토_채팅방) - .contents("엔초가 지토에게 5시애 보낸 쪽지") - .writer(엔초) - .receiver(지토) - .build(); - + .chatRoom(엔초_지토_채팅방) + .contents("엔초가 지토에게 5시애 보낸 쪽지") + .writer(엔초) + .receiver(지토) + .build(); + 엔초가_지토에게_추가로_보낸_쪽지 = Message.builder() + .chatRoom(엔초_지토_채팅방) + .contents("엔초가 지토에게 6시애 보낸 쪽지") + .writer(엔초) + .receiver(지토) + .build(); + 메리가_엔초에게_3시에_보낸_쪽지1 = Message.builder() + .chatRoom(메리_엔초_채팅방) + .contents("메리가 엔초에게 3시에 보낸 쪽지") + .writer(메리) + .receiver(엔초) + .build(); + 메리가_엔초에게_3시에_보낸_쪽지1 = Message.builder() + .chatRoom(메리_엔초_채팅방) + .contents("메리가 엔초에게 3시에 보낸 쪽지2") + .writer(메리) + .receiver(엔초) + .build(); + 메리가_엔초에게_3시에_보낸_쪽지2 = Message.builder() + .chatRoom(메리_엔초_채팅방) + .contents("메리가 엔초에게 3시에 보낸 쪽지3") + .writer(메리) + .receiver(엔초) + .build(); + 메리가_엔초에게_3시에_보낸_쪽지3 = Message.builder() + .chatRoom(메리_엔초_채팅방) + .contents("메리가 엔초에게 3시에 보낸 쪽지3") + .writer(메리) + .receiver(엔초) + .build(); + 엔초가_메리에게_3시에_보낸_쪽지 = Message.builder() + .chatRoom(메리_엔초_채팅방) + .contents("엔초가 메리에게 3시에 보낸 쪽지3") + .writer(엔초) + .receiver(메리) + .build(); 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); categoryRepository.save(전자기기_카테고리); @@ -206,7 +240,6 @@ void setUp() { List.of( 제이미가_엔초에게_1시에_보낸_쪽지, 엔초가_지토에게_2시에_보낸_쪽지, - 메리가_엔초에게_3시에_보낸_쪽지, 제이미가_엔초에게_4시에_보낸_쪽지, 엔초가_지토에게_5시에_보낸_쪽지 ) From d90c03cbc5d6cc8dc0747a6b9db07dff491215ac Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 20:09:23 +0900 Subject: [PATCH 06/29] =?UTF-8?q?feat:=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=9C=20=EC=B0=B8=EC=97=AC=EC=9E=90?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EC=83=9D=EC=84=B1=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/application/ChatRoomService.java | 28 +++++++++++-- .../chat/application/ChatRoomServiceTest.java | 29 +++++++++++++ .../fixture/ChatRoomServiceFixture.java | 42 +++++++++++++++++-- 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index efb3d78d6..b3b49cf01 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -13,11 +13,13 @@ import com.ddang.ddang.chat.application.exception.InvalidAuctionToChatException; import com.ddang.ddang.chat.application.exception.InvalidUserToChat; import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.ReadMessageLog; import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; import com.ddang.ddang.chat.domain.repository.ChatRoomAndImageRepository; import com.ddang.ddang.chat.domain.repository.ChatRoomAndMessageAndImageRepository; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -27,6 +29,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; @Service @Transactional(readOnly = true) @@ -38,6 +41,7 @@ public class ChatRoomService { private final ChatRoomRepository chatRoomRepository; private final ChatRoomAndImageRepository chatRoomAndImageRepository; private final ChatRoomAndMessageAndImageRepository chatRoomAndMessageAndImageRepository; + private final ReadMessageLogRepository readMessageLogRepository; private final UserRepository userRepository; private final AuctionRepository auctionRepository; @@ -50,10 +54,26 @@ public Long create(final Long userId, final CreateChatRoomDto chatRoomDto) { new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.") ); - return chatRoomRepository.findChatRoomIdByAuctionId(findAuction.getId()) - .orElseGet(() -> - persistChatRoom(findUser, findAuction).getId() - ); + final Optional findChatRoom = chatRoomRepository.findChatRoomByAuctionId(findAuction.getId()); + if (findChatRoom.isPresent()) { + return findChatRoom.get().getId(); + } + + return createChatRoom(findUser, findAuction); + } + + private Long createChatRoom(final User findUser, final Auction findAuction) { + final ChatRoom persistChatRoom = persistChatRoom(findUser, findAuction); + createReadMessageLog(persistChatRoom); + return persistChatRoom.getId(); + } + + private void createReadMessageLog(final ChatRoom persistChatRoom) { + final ReadMessageLog buyerReadMessageLog = new ReadMessageLog(persistChatRoom, persistChatRoom.getBuyer()); + final ReadMessageLog sellerReadMessageLog = new ReadMessageLog(persistChatRoom, persistChatRoom.getAuction() + .getSeller()); + readMessageLogRepository.save(buyerReadMessageLog); + readMessageLogRepository.save(sellerReadMessageLog); } private ChatRoom persistChatRoom(final User user, final Auction auction) { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java index de0cccb21..c06a617ec 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java @@ -9,6 +9,9 @@ import com.ddang.ddang.chat.application.exception.InvalidAuctionToChatException; import com.ddang.ddang.chat.application.exception.InvalidUserToChat; import com.ddang.ddang.chat.application.fixture.ChatRoomServiceFixture; +import com.ddang.ddang.chat.domain.ReadMessageLog; +import com.ddang.ddang.chat.domain.repository.MessageRepository; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.user.application.exception.UserNotFoundException; import org.assertj.core.api.SoftAssertions; @@ -18,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -30,6 +34,31 @@ class ChatRoomServiceTest extends ChatRoomServiceFixture { @Autowired ChatRoomService chatRoomService; + @Autowired + MessageService messageService; + + @Autowired + ReadMessageLogRepository readMessageLogRepository; + + @Autowired + MessageRepository messageRepository; + + @Test + void 채팅방_생성시_채팅_참여자에_대한_로그를_생성한다() { + // given + final Long createdChatRoomId = chatRoomService.create(채팅방을_생성하는_메리.getId(), 메리가_생성하려는_채팅방); + + // when + final Optional actual_메리 = readMessageLogRepository.findBy(채팅방을_생성하는_메리.getId(), createdChatRoomId); + final Optional actual_지토 = readMessageLogRepository.findBy(메리_경매_낙찰자_지토.getId(), createdChatRoomId); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual_메리).isPresent(); + softAssertions.assertThat(actual_지토).isPresent(); + }); + } + @Test void 채팅방을_생성한다() { // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java index 234913411..e53afed2b 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java @@ -59,6 +59,8 @@ public class ChatRoomServiceFixture { protected User 엔초; protected User 제이미; protected User 지토; + protected User 채팅방을_생성하는_메리; + protected User 메리_경매_낙찰자_지토; protected User 경매에_참여한_적_없는_사용자; protected Auction 채팅방이_없는_경매; protected Auction 판매자_엔초_구매자_지토_경매; @@ -78,6 +80,7 @@ public class ChatRoomServiceFixture { protected CreateChatRoomDto 경매가_진행중이라서_채팅방을_생성할_수_없는_DTO; protected CreateChatRoomDto 낙찰자가_없어서_채팅방을_생성할_수_없는_DTO; protected CreateChatRoomDto 엔초_지토_채팅방_생성을_위한_DTO; + protected CreateChatRoomDto 메리가_생성하려는_채팅방; protected ReadParticipatingChatRoomDto 엔초가_조회한_엔초_지토_채팅방_정보_조회_결과; protected ReadChatRoomDto 엔초_지토_채팅방_정보_및_참여_가능; protected ReadChatRoomDto 엔초_지토_채팅방_정보_및_참여_불가능; @@ -120,32 +123,46 @@ void setUp() { .name("엔초") .profileImage(프로필_이미지) .reliability(new Reliability(4.7d)) - .oauthId("12346") + .oauthId("12347") .build(); 제이미 = User.builder() .name("제이미") .profileImage(프로필_이미지) .reliability(new Reliability(4.7d)) - .oauthId("12347") + .oauthId("12348") .build(); 지토 = User.builder() .name("지토") .profileImage(프로필_이미지) .reliability(new Reliability(4.7d)) - .oauthId("12348") + .oauthId("12349") .build(); 경매에_참여한_적_없는_사용자 = User.builder() .name("외부인") .profileImage(프로필_이미지) .reliability(new Reliability(4.7d)) - .oauthId("12349") + .oauthId("12340") .build(); + 채팅방을_생성하는_메리 = User.builder() + .name("채팅방을_생성하는_메리") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("09876") + .build(); + 메리_경매_낙찰자_지토 = User.builder() + .name("메리_경매_낙찰자_지토") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("10293") + .build(); userRepository.save(판매자); userRepository.save(구매자); userRepository.save(엔초); userRepository.save(제이미); userRepository.save(지토); userRepository.save(경매에_참여한_적_없는_사용자); + userRepository.save(채팅방을_생성하는_메리); + userRepository.save(메리_경매_낙찰자_지토); 채팅방이_없는_경매 = Auction.builder() .seller(판매자) @@ -192,25 +209,39 @@ void setUp() { .bidUnit(new BidUnit(1_000)) .closingTime(LocalDateTime.now()) .build(); + final Auction 판매자_메리_구매자_지토_경매 = Auction.builder() + .seller(채팅방을_생성하는_메리) + .title("메리 맥북") + .description("메리 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); 채팅방이_없는_경매.addAuctionImages(List.of(경매_대표_이미지, 대표_이미지가_아닌_경매_이미지)); 판매자_엔초_구매자_지토_경매.addAuctionImages(List.of(엔초의_경매_대표_이미지, 엔초의_대표_이미지가_아닌_경매_이미지)); 판매자_제이미_구매자_엔초_경매.addAuctionImages(List.of(제이미의_경매_대표_이미지, 제이미의_대표_이미지가_아닌_경매_이미지)); + 판매자_메리_구매자_지토_경매.addAuctionImages(List.of(경매_대표_이미지, 대표_이미지가_아닌_경매_이미지)); auctionRepository.save(채팅방이_없는_경매); auctionRepository.save(종료되지_않은_경매); auctionRepository.save(낙찰자가_없는_경매); auctionRepository.save(판매자_엔초_구매자_지토_경매); auctionRepository.save(판매자_제이미_구매자_엔초_경매); + auctionRepository.save(판매자_메리_구매자_지토_경매); final Bid 채팅방_없는_경매_입찰 = new Bid(채팅방이_없는_경매, 구매자, new BidPrice(15_000)); final Bid 지토가_엔초_경매에_입찰 = new Bid(판매자_엔초_구매자_지토_경매, 지토, new BidPrice(15_000)); final Bid 엔초가_제이미_경매에_입찰 = new Bid(판매자_제이미_구매자_엔초_경매, 엔초, new BidPrice(15_000)); + final Bid 지토가_메리_경매에_입찰 = new Bid(판매자_메리_구매자_지토_경매, 메리_경매_낙찰자_지토, new BidPrice(15_000)); bidRepository.save(채팅방_없는_경매_입찰); bidRepository.save(지토가_엔초_경매에_입찰); bidRepository.save(엔초가_제이미_경매에_입찰); + bidRepository.save(지토가_메리_경매에_입찰); 채팅방이_없는_경매.updateLastBid(채팅방_없는_경매_입찰); 판매자_엔초_구매자_지토_경매.updateLastBid(지토가_엔초_경매에_입찰); 판매자_제이미_구매자_엔초_경매.updateLastBid(엔초가_제이미_경매에_입찰); + 판매자_메리_구매자_지토_경매.updateLastBid(지토가_메리_경매에_입찰); 엔초_지토_채팅방 = new ChatRoom(판매자_엔초_구매자_지토_경매, 지토); 제이미_엔초_채팅방 = new ChatRoom(판매자_제이미_구매자_엔초_경매, 엔초); @@ -239,6 +270,7 @@ void setUp() { 경매에_참여한_적_없는_사용자_정보 = new AuthenticationUserInfo(경매에_참여한_적_없는_사용자.getId()); 존재하지_않는_사용자_정보 = new AuthenticationUserInfo(존재하지_않는_사용자_아이디); 채팅방_생성을_위한_DTO = new CreateChatRoomDto(채팅방이_없는_경매.getId()); + 메리가_생성하려는_채팅방 = new CreateChatRoomDto(판매자_메리_구매자_지토_경매.getId()); 경매_정보가_없어서_채팅방을_생성할_수_없는_DTO = new CreateChatRoomDto(존재하지_않는_경매_아이디); 경매가_진행중이라서_채팅방을_생성할_수_없는_DTO = new CreateChatRoomDto(종료되지_않은_경매.getId()); 낙찰자가_없어서_채팅방을_생성할_수_없는_DTO = new CreateChatRoomDto(낙찰자가_없는_경매.getId()); @@ -253,6 +285,7 @@ void setUp() { ReadAuctionInChatRoomDto.of(판매자_제이미_구매자_엔초_경매, 제이미의_경매_대표_이미지), ReadUserInChatRoomDto.from(제이미), ReadLastMessageDto.from(제이미가_엔초에게_2시에_보낸_쪽지), + 1L, true ); 엔초_채팅_목록의_엔초_지토_채팅방_정보 = new ReadChatRoomWithLastMessageDto( @@ -260,6 +293,7 @@ void setUp() { ReadAuctionInChatRoomDto.of(판매자_엔초_구매자_지토_경매, 엔초의_경매_대표_이미지), ReadUserInChatRoomDto.from(지토), ReadLastMessageDto.from(엔초가_지토에게_1시에_보낸_쪽지), + 1L, true ); } From 3f8d43127674572a470c4e0658382fc7b49ce271 Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 20:10:58 +0900 Subject: [PATCH 07/29] =?UTF-8?q?feat:=20=EA=B2=BD=EB=A7=A4=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EB=94=94=EB=A1=9C=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/chat/domain/repository/ChatRoomRepository.java | 2 ++ .../persistence/ChatRoomRepositoryImpl.java | 5 +++++ .../persistence/JpaChatRoomRepository.java | 9 +++++++++ 3 files changed, 16 insertions(+) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java index 3935ababc..d06351532 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java @@ -10,6 +10,8 @@ public interface ChatRoomRepository { Optional findById(final Long id); + Optional findChatRoomByAuctionId(final Long auctionId); + Optional findChatRoomIdByAuctionId(final Long auctionId); boolean existsByAuctionId(final Long auctionId); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java index a2d88ceb8..78dc8754c 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java @@ -23,6 +23,11 @@ public Optional findById(final Long id) { return jpaChatRoomRepository.findById(id); } + @Override + public Optional findChatRoomByAuctionId(final Long auctionId) { + return jpaChatRoomRepository.findChatRoomByAuctionId(auctionId); + } + @Override public Optional findChatRoomIdByAuctionId(final Long auctionId) { return jpaChatRoomRepository.findChatRoomIdByAuctionId(auctionId); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java index 639a831ca..def135423 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java @@ -8,6 +8,15 @@ public interface JpaChatRoomRepository extends JpaRepository { + @Query(""" + SELECT c + FROM ChatRoom c + JOIN FETCH c.buyer + JOIN FETCH c.auction.seller + WHERE c.auction.id = :auctionId + """) + Optional findChatRoomByAuctionId(final Long auctionId); + @Query(""" SELECT c.id FROM ChatRoom c From e0ef4e8b6dcffea6a68aae757fafbd2c45c8d776 Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 20:12:38 +0900 Subject: [PATCH 08/29] =?UTF-8?q?feat:=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=EA=B0=92=EC=97=90=20=EC=95=88=20=EC=9D=BD=EC=9D=80=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EA=B0=9C=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/application/dto/ReadChatRoomWithLastMessageDto.java | 3 +++ .../chat/presentation/fixture/ChatRoomControllerFixture.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadChatRoomWithLastMessageDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadChatRoomWithLastMessageDto.java index 36e3d0382..b52e55a9e 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadChatRoomWithLastMessageDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadChatRoomWithLastMessageDto.java @@ -11,6 +11,7 @@ public record ReadChatRoomWithLastMessageDto( ReadAuctionInChatRoomDto auctionDto, ReadUserInChatRoomDto partnerDto, ReadLastMessageDto lastMessageDto, + Long unreadMessageCount, boolean isChatAvailable ) { @@ -22,12 +23,14 @@ public static ReadChatRoomWithLastMessageDto of( final User partner = chatRoom.calculateChatPartnerOf(findUser); final Message lastMessage = chatRoomAndMessageAndImageDto.message(); final AuctionImage thumbnailImage = chatRoomAndMessageAndImageDto.thumbnailImage(); + final Long unreadMessages = chatRoomAndMessageAndImageDto.unreadMessageCount(); return new ReadChatRoomWithLastMessageDto( chatRoom.getId(), ReadAuctionInChatRoomDto.of(chatRoom.getAuction(), thumbnailImage), ReadUserInChatRoomDto.from(partner), ReadLastMessageDto.from(lastMessage), + unreadMessages, chatRoom.isChatAvailablePartner(partner) ); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/presentation/fixture/ChatRoomControllerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/presentation/fixture/ChatRoomControllerFixture.java index 8f7b5ddaa..6d83db0e4 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/presentation/fixture/ChatRoomControllerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/presentation/fixture/ChatRoomControllerFixture.java @@ -23,8 +23,8 @@ public class ChatRoomControllerFixture extends CommonControllerSliceTest { private ReadUserInChatRoomDto 구매자2 = new ReadUserInChatRoomDto(3L, "구매자2", 3L, 5.0d, false); private ReadAuctionInChatRoomDto 조회용_경매1 = new ReadAuctionInChatRoomDto(1L, "경매1", 10_000, 1L); private ReadAuctionInChatRoomDto 조회용_경매2 = new ReadAuctionInChatRoomDto(2L, "경매2", 20_000, 1L); - protected ReadChatRoomWithLastMessageDto 조회용_채팅방1 = new ReadChatRoomWithLastMessageDto(1L, 조회용_경매1, 구매자1, new ReadLastMessageDto(1L, LocalDateTime.now(), 판매자, 구매자1, "메시지1"), true); - protected ReadChatRoomWithLastMessageDto 조회용_채팅방2 = new ReadChatRoomWithLastMessageDto(2L, 조회용_경매2, 구매자2, new ReadLastMessageDto(1L, LocalDateTime.now(), 판매자, 구매자2, "메시지2"), true); + protected ReadChatRoomWithLastMessageDto 조회용_채팅방1 = new ReadChatRoomWithLastMessageDto(1L, 조회용_경매1, 구매자1, new ReadLastMessageDto(1L, LocalDateTime.now(), 판매자, 구매자1, "메시지1"), 1L, true); + protected ReadChatRoomWithLastMessageDto 조회용_채팅방2 = new ReadChatRoomWithLastMessageDto(2L, 조회용_경매2, 구매자2, new ReadLastMessageDto(1L, LocalDateTime.now(), 판매자, 구매자2, "메시지2"), 1L, true); protected CreateMessageRequest 메시지_생성_요청 = new CreateMessageRequest(1L, "메시지 내용"); protected CreateMessageRequest 유효하지_않은_발신자의_메시지_생성_요청 = new CreateMessageRequest(-999L, "메시지 내용"); protected CreateMessageRequest 탈퇴한_사용자와의_메시지_생성_요청 = new CreateMessageRequest(탈퇴한_사용자_아이디, "메시지 내용"); From 5e229865c115e311ec4c531c69b28ae0b14a17d3 Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 20:13:40 +0900 Subject: [PATCH 09/29] =?UTF-8?q?refactor:=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=20=EB=A1=9C=EA=B7=B8=20=EC=A1=B0=ED=9A=8C=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ReadMessageLogRepository.java | 2 +- .../ReadMessageLogRepositoryImpl.java | 2 +- .../ReadMessageLogRepositoryFixture.java | 50 +++++++++++++++---- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java index 1e254efdd..7336fa340 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java @@ -8,5 +8,5 @@ public interface ReadMessageLogRepository { ReadMessageLog save(final ReadMessageLog readMessageLog); - Optional findLastReadMessageBy(final Long readerId, final Long chatRoomId); + Optional findBy(final Long readerId, final Long chatRoomId); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java index 77a3eeb00..bab34022f 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java @@ -19,7 +19,7 @@ public ReadMessageLog save(final ReadMessageLog readMessageLog) { } @Override - public Optional findLastReadMessageBy(final Long readerId, final Long chatRoomId) { + public Optional findBy(final Long readerId, final Long chatRoomId) { return jpaReadMessageLogRepository.findLastReadMessageByUserIdAndChatRoomId(readerId, chatRoomId); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java index 5766113f9..1c140fbba 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java @@ -4,9 +4,14 @@ import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; import com.ddang.ddang.bid.domain.repository.BidRepository; +import com.ddang.ddang.bid.infrastructure.persistence.BidRepositoryImpl; +import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.chat.domain.ChatRoom; @@ -14,11 +19,21 @@ import com.ddang.ddang.chat.domain.ReadMessageLog; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.chat.domain.repository.MessageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.ChatRoomRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.JpaReadMessageLogRepository; +import com.ddang.ddang.chat.infrastructure.persistence.MessageRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.QuerydslMessageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.ReadMessageLogRepositoryImpl; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -28,24 +43,21 @@ public class ReadMessageLogRepositoryFixture { - @Autowired - private AuctionRepository auctionRepository; - @Autowired private JpaCategoryRepository categoryRepository; - @Autowired + private AuctionRepository auctionRepository; + private UserRepository userRepository; - @Autowired private BidRepository bidRepository; - @Autowired private ChatRoomRepository chatRoomRepository; - @Autowired private MessageRepository messageRepository; + private ReadMessageLogRepositoryImpl readMessageLogRepository; + protected ChatRoom 메리_엔초_채팅방; protected User 메리; protected User 엔초; @@ -57,7 +69,22 @@ public class ReadMessageLogRepositoryFixture { protected ProfileImage 프로필_이미지 = new ProfileImage("upload.png", "store.png"); @BeforeEach - void setUp() { + void fixtureSetUp( + @Autowired final JPAQueryFactory jpaQueryFactory, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaBidRepository jpaBidRepository, + @Autowired final JpaChatRoomRepository jpaChatRoomRepository, + @Autowired final JpaMessageRepository jpaMessageRepository, + @Autowired final JpaReadMessageLogRepository jpaReadMessageLogRepository + ) { + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); + userRepository = new UserRepositoryImpl(jpaUserRepository); + bidRepository = new BidRepositoryImpl(jpaBidRepository); + chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + messageRepository = new MessageRepositoryImpl(jpaMessageRepository, new QuerydslMessageRepository(jpaQueryFactory)); + readMessageLogRepository = new ReadMessageLogRepositoryImpl(jpaReadMessageLogRepository); + final Category 전자기기_카테고리 = new Category("전자기기"); final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); @@ -111,6 +138,11 @@ void setUp() { } 다섯_번째_메시지 = 메리_엔초_메시지들.get(4); - 다섯_번째_메시지까지_읽은_메시지_로그 = new ReadMessageLog(메리_엔초_채팅방, 메리, 다섯_번째_메시지); + 다섯_번째_메시지까지_읽은_메시지_로그 = new ReadMessageLog(메리_엔초_채팅방, 메리); + 다섯_번째_메시지까지_읽은_메시지_로그.updateLastReadMessage(다섯_번째_메시지.getId()); + + final ReadMessageLog 메리_엔초_채팅방의_메리_메시지_조회_로그 = new ReadMessageLog(메리_엔초_채팅방, 메리); + 메리_엔초_채팅방의_메리_메시지_조회_로그.updateLastReadMessage(다섯_번째_메시지.getId()); + readMessageLogRepository.save(메리_엔초_채팅방의_메리_메시지_조회_로그); } } From b14e7ab2e8deeac4bdd9c23f024fb6964779a01d Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 20:15:26 +0900 Subject: [PATCH 10/29] =?UTF-8?q?feat:=20=EC=96=B4=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/fixture/ReadMessageLogRepositoryFixture.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java index 1c140fbba..71a594bad 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.List; +@SuppressWarnings("NonAsciiCharacters") public class ReadMessageLogRepositoryFixture { @Autowired From 049fa04d1676a7a3fa2a04e6f9b3c5a5cad5d47e Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 20:17:42 +0900 Subject: [PATCH 11/29] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=20=EC=B0=BE?= =?UTF-8?q?=EC=A7=80=20=EB=AA=BB=ED=95=9C=20=EA=B2=BD=EC=9A=B0=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadMessageLogNotFoundException.java | 8 ++++++++ .../ddang/exception/GlobalExceptionHandler.java | 9 +++++++++ .../ReadMessageLogRepositoryImplTest.java | 16 +++++++++++----- 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/application/exception/ReadMessageLogNotFoundException.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/exception/ReadMessageLogNotFoundException.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/exception/ReadMessageLogNotFoundException.java new file mode 100644 index 000000000..45eb4623f --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/exception/ReadMessageLogNotFoundException.java @@ -0,0 +1,8 @@ +package com.ddang.ddang.chat.application.exception; + +public class ReadMessageLogNotFoundException extends IllegalArgumentException { + + public ReadMessageLogNotFoundException(final String message) { + super(message); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java b/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java index 9cfdd446e..1bf97028e 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java @@ -15,6 +15,7 @@ import com.ddang.ddang.chat.application.exception.InvalidAuctionToChatException; import com.ddang.ddang.chat.application.exception.InvalidUserToChat; import com.ddang.ddang.chat.application.exception.MessageNotFoundException; +import com.ddang.ddang.chat.application.exception.ReadMessageLogNotFoundException; import com.ddang.ddang.chat.application.exception.UnableToChatException; import com.ddang.ddang.device.application.exception.DeviceTokenNotFoundException; import com.ddang.ddang.exception.dto.ExceptionResponse; @@ -110,6 +111,14 @@ public ResponseEntity handleMessageNotFoundException(final Me .body(new ExceptionResponse(ex.getMessage())); } + @ExceptionHandler(ReadMessageLogNotFoundException.class) + public ResponseEntity handleReadMessageNotFoundException(final ReadMessageLogNotFoundException ex) { + logger.warn(String.format(LOG_MESSAGE_FORMAT, ex.getClass().getSimpleName(), ex.getMessage())); + + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(new ExceptionResponse(ex.getMessage())); + } + @ExceptionHandler(UnableToChatException.class) public ResponseEntity handleUnableToChatException(final UnableToChatException ex) { logger.warn(String.format(LOG_MESSAGE_FORMAT, ex.getClass().getSimpleName(), ex.getMessage())); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java index 549ceda1b..758d1c064 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java @@ -4,7 +4,9 @@ import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.chat.infrastructure.persistence.fixture.ReadMessageLogRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -17,14 +19,18 @@ import static org.assertj.core.api.Assertions.assertThat; @DataJpaTest -@Import({JpaConfiguration.class}) +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") class ReadMessageLogRepositoryImplTest extends ReadMessageLogRepositoryFixture { - @Autowired ReadMessageLogRepository readMessageLogRepository; + @BeforeEach + void setUp(@Autowired final JpaReadMessageLogRepository jpaReadMessageLogRepository) { + readMessageLogRepository = new ReadMessageLogRepositoryImpl(jpaReadMessageLogRepository); + } + @Test void 마지막_읽은_메시지를_저장한다() { // given @@ -35,14 +41,14 @@ class ReadMessageLogRepositoryImplTest extends ReadMessageLogRepositoryFixture { } @Test - void 메시지_조회자_아이디와_채팅방_아이디에_해당하는_마지막_메시지를_반환한다() { + void 메시지_조회자_아이디와_채팅방_아이디에_해당하는_조회_메시지_로그를_반환한다() { // given - final Optional actual = readMessageLogRepository.findLastReadMessageBy(메리.getId(), 메리_엔초_채팅방.getId()); + final Optional actual = readMessageLogRepository.findBy(메리.getId(), 메리_엔초_채팅방.getId()); // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).isPresent(); - softAssertions.assertThat(actual.get().getLastReadMessage().getId()).isEqualTo(다섯_번째_메시지.getId()); + softAssertions.assertThat(actual.get().getLastReadMessageId()).isEqualTo(다섯_번째_메시지.getId()); }); } } From 0e72381ec23dc47eef508827d8ec664389d90714 Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 21:19:23 +0900 Subject: [PATCH 12/29] =?UTF-8?q?refactor:=20=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/application/ChatRoomService.java | 16 +++---- .../LastReadMessageLogEventListener.java | 29 ++++++++++++ .../LastReadMessageLogService.java | 44 +++++++++++++++++++ .../chat/application/MessageService.java | 24 ++++------ .../event/CreateReadMessageLogEvent.java | 6 +++ .../event/UpdateReadMessageLogEvent.java | 8 ++++ .../chat/application/ChatRoomServiceTest.java | 31 ++++++++++++- .../chat/application/MessageServiceTest.java | 19 +++++--- 8 files changed, 144 insertions(+), 33 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/CreateReadMessageLogEvent.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/UpdateReadMessageLogEvent.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index b3b49cf01..8f8d8e222 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -9,11 +9,11 @@ import com.ddang.ddang.chat.application.dto.CreateChatRoomDto; import com.ddang.ddang.chat.application.dto.ReadChatRoomWithLastMessageDto; import com.ddang.ddang.chat.application.dto.ReadParticipatingChatRoomDto; +import com.ddang.ddang.chat.application.event.CreateReadMessageLogEvent; import com.ddang.ddang.chat.application.exception.ChatRoomNotFoundException; import com.ddang.ddang.chat.application.exception.InvalidAuctionToChatException; import com.ddang.ddang.chat.application.exception.InvalidUserToChat; import com.ddang.ddang.chat.domain.ChatRoom; -import com.ddang.ddang.chat.domain.ReadMessageLog; import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; import com.ddang.ddang.chat.domain.repository.ChatRoomAndImageRepository; @@ -24,6 +24,7 @@ import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -38,6 +39,7 @@ public class ChatRoomService { private static final Long DEFAULT_CHAT_ROOM_ID = null; + private final ApplicationEventPublisher messageLogEventPublisher; private final ChatRoomRepository chatRoomRepository; private final ChatRoomAndImageRepository chatRoomAndImageRepository; private final ChatRoomAndMessageAndImageRepository chatRoomAndMessageAndImageRepository; @@ -64,16 +66,10 @@ public Long create(final Long userId, final CreateChatRoomDto chatRoomDto) { private Long createChatRoom(final User findUser, final Auction findAuction) { final ChatRoom persistChatRoom = persistChatRoom(findUser, findAuction); - createReadMessageLog(persistChatRoom); - return persistChatRoom.getId(); - } - private void createReadMessageLog(final ChatRoom persistChatRoom) { - final ReadMessageLog buyerReadMessageLog = new ReadMessageLog(persistChatRoom, persistChatRoom.getBuyer()); - final ReadMessageLog sellerReadMessageLog = new ReadMessageLog(persistChatRoom, persistChatRoom.getAuction() - .getSeller()); - readMessageLogRepository.save(buyerReadMessageLog); - readMessageLogRepository.save(sellerReadMessageLog); + messageLogEventPublisher.publishEvent(new CreateReadMessageLogEvent(persistChatRoom)); + + return persistChatRoom.getId(); } private ChatRoom persistChatRoom(final User user, final Auction auction) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java new file mode 100644 index 000000000..1be82cb6d --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java @@ -0,0 +1,29 @@ +package com.ddang.ddang.chat.application; + +import com.ddang.ddang.chat.application.event.CreateReadMessageLogEvent; +import com.ddang.ddang.chat.application.event.UpdateReadMessageLogEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +@Slf4j +public class LastReadMessageLogEventListener { + + private final LastReadMessageLogService lastReadMessageLogService; + + @EventListener + @Transactional + public void create(final CreateReadMessageLogEvent createReadMessageLogEvent) { + lastReadMessageLogService.create(createReadMessageLogEvent); + } + + @EventListener + @Transactional + public void update(final UpdateReadMessageLogEvent updateReadMessageLogEvent) { + lastReadMessageLogService.update(updateReadMessageLogEvent); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java new file mode 100644 index 000000000..557d705e0 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java @@ -0,0 +1,44 @@ +package com.ddang.ddang.chat.application; + +import com.ddang.ddang.chat.application.event.CreateReadMessageLogEvent; +import com.ddang.ddang.chat.application.event.UpdateReadMessageLogEvent; +import com.ddang.ddang.chat.application.exception.ReadMessageLogNotFoundException; +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.ReadMessageLog; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; +import com.ddang.ddang.user.domain.User; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class LastReadMessageLogService { + + private final ReadMessageLogRepository readMessageLogRepository; + + @Transactional + public void create(final CreateReadMessageLogEvent createReadMessageLogEvent) { + final ChatRoom chatRoom = createReadMessageLogEvent.chatRoom(); + final User buyer = chatRoom.getBuyer(); + final User seller = chatRoom.getAuction().getSeller(); + final ReadMessageLog buyerReadMessageLog = new ReadMessageLog(chatRoom, buyer); + final ReadMessageLog sellerReadMessageLog = new ReadMessageLog(chatRoom, seller); + + readMessageLogRepository.save(buyerReadMessageLog); + readMessageLogRepository.save(sellerReadMessageLog); + } + + @Transactional + public void update(final UpdateReadMessageLogEvent createReadMessageLogEvent) { + final User reader = createReadMessageLogEvent.reader(); + final ChatRoom chatRoom = createReadMessageLogEvent.chatRoom(); + final ReadMessageLog messageLog = readMessageLogRepository.findBy(reader.getId(), chatRoom.getId()) + .orElseThrow(() -> + new ReadMessageLogNotFoundException( + "메시지 조회 로그가 존재하지 않습니다." + )); + messageLog.updateLastReadMessage(createReadMessageLogEvent.lastReadMessage().getId()); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index e6239353f..c9683ee25 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -3,16 +3,14 @@ import com.ddang.ddang.chat.application.dto.CreateMessageDto; import com.ddang.ddang.chat.application.dto.ReadMessageDto; import com.ddang.ddang.chat.application.event.MessageNotificationEvent; +import com.ddang.ddang.chat.application.event.UpdateReadMessageLogEvent; import com.ddang.ddang.chat.application.exception.ChatRoomNotFoundException; import com.ddang.ddang.chat.application.exception.MessageNotFoundException; -import com.ddang.ddang.chat.application.exception.ReadMessageLogNotFoundException; import com.ddang.ddang.chat.application.exception.UnableToChatException; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; -import com.ddang.ddang.chat.domain.ReadMessageLog; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.chat.domain.repository.MessageRepository; -import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.chat.presentation.dto.request.ReadMessageRequest; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; @@ -31,9 +29,9 @@ @Slf4j public class MessageService { - private final ApplicationEventPublisher messageEventPublisher; + private final ApplicationEventPublisher messageLogEventPublisher; + private final ApplicationEventPublisher messageNotificationEventPublisher; private final MessageRepository messageRepository; - private final ReadMessageLogRepository readMessageLogRepository; private final ChatRoomRepository chatRoomRepository; private final UserRepository userRepository; @@ -57,7 +55,7 @@ public Long create(final CreateMessageDto dto, final String profileImageAbsolute final Message persistMessage = messageRepository.save(message); - messageEventPublisher.publishEvent(new MessageNotificationEvent(persistMessage, profileImageAbsoluteUrl)); + messageNotificationEventPublisher.publishEvent(new MessageNotificationEvent(persistMessage, profileImageAbsoluteUrl)); return persistMessage.getId(); } @@ -80,22 +78,16 @@ public List readAllByLastMessageId(final ReadMessageRequest requ request.lastMessageId() ); - final Message lastReadMessage = readMessages.get(readMessages.size() - 1); - updateLastReadMessage(reader, chatRoom, lastReadMessage); + if (readMessages.size() > 0) { + final Message lastReadMessage = readMessages.get(readMessages.size() - 1); + messageLogEventPublisher.publishEvent(new UpdateReadMessageLogEvent(reader, chatRoom, lastReadMessage)); + } return readMessages.stream() .map(message -> ReadMessageDto.from(message, chatRoom)) .toList(); } - private void updateLastReadMessage(final User reader, final ChatRoom chatRoom, final Message lastReadMessage) { - final ReadMessageLog messageLog = readMessageLogRepository.findBy(reader.getId(), chatRoom.getId()) - .orElseThrow(() -> new ReadMessageLogNotFoundException( - "메시지 조회 로그가 존재하지 않습니다." - )); - messageLog.updateLastReadMessage(lastReadMessage.getId()); - } - private void validateLastMessageId(final Long lastMessageId) { if (!messageRepository.existsById(lastMessageId)) { throw new MessageNotFoundException("조회한 마지막 메시지가 존재하지 않습니다."); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/CreateReadMessageLogEvent.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/CreateReadMessageLogEvent.java new file mode 100644 index 000000000..fec66ac3a --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/CreateReadMessageLogEvent.java @@ -0,0 +1,6 @@ +package com.ddang.ddang.chat.application.event; + +import com.ddang.ddang.chat.domain.ChatRoom; + +public record CreateReadMessageLogEvent(ChatRoom chatRoom) { +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/UpdateReadMessageLogEvent.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/UpdateReadMessageLogEvent.java new file mode 100644 index 000000000..8fd1cde98 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/UpdateReadMessageLogEvent.java @@ -0,0 +1,8 @@ +package com.ddang.ddang.chat.application.event; + +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.user.domain.User; + +public record UpdateReadMessageLogEvent(User reader, ChatRoom chatRoom, Message lastReadMessage) { +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java index c06a617ec..f8d97e30f 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java @@ -5,6 +5,7 @@ import com.ddang.ddang.auction.domain.exception.WinnerNotFoundException; import com.ddang.ddang.chat.application.dto.ReadChatRoomWithLastMessageDto; import com.ddang.ddang.chat.application.dto.ReadParticipatingChatRoomDto; +import com.ddang.ddang.chat.application.event.CreateReadMessageLogEvent; import com.ddang.ddang.chat.application.exception.ChatRoomNotFoundException; import com.ddang.ddang.chat.application.exception.InvalidAuctionToChatException; import com.ddang.ddang.chat.application.exception.InvalidUserToChat; @@ -19,14 +20,18 @@ import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.event.ApplicationEvents; +import org.springframework.test.context.event.RecordApplicationEvents; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @IsolateDatabase +@RecordApplicationEvents @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") class ChatRoomServiceTest extends ChatRoomServiceFixture { @@ -43,6 +48,9 @@ class ChatRoomServiceTest extends ChatRoomServiceFixture { @Autowired MessageRepository messageRepository; + @Autowired + ApplicationEvents events; + @Test void 채팅방_생성시_채팅_참여자에_대한_로그를_생성한다() { // given @@ -68,6 +76,16 @@ class ChatRoomServiceTest extends ChatRoomServiceFixture { assertThat(actual).isPositive(); } + @Test + void 채팅방_생성시_메시지_로그_생성_이벤트가_호출된다() { + // when + chatRoomService.create(구매자.getId(), 채팅방_생성을_위한_DTO); + final long actual = events.stream(CreateReadMessageLogEvent.class).count(); + + // then + assertThat(actual).isEqualTo(1); + } + @Test void 채팅방_생성시_요청한_사용자_정보를_찾을_수_없다면_예외가_발생한다() { // when & then @@ -125,8 +143,17 @@ class ChatRoomServiceTest extends ChatRoomServiceFixture { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(2); - softAssertions.assertThat(actual.get(0)).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보); - softAssertions.assertThat(actual.get(1)).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보); + softAssertions.assertThat(actual.get(0).id()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.id()); + softAssertions.assertThat(actual.get(0).auctionDto()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.auctionDto()); + softAssertions.assertThat(actual.get(0).partnerDto()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.partnerDto()); + softAssertions.assertThat(actual.get(0).lastMessageDto()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.lastMessageDto()); + softAssertions.assertThat(actual.get(0).isChatAvailable()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.isChatAvailable()); + + softAssertions.assertThat(actual.get(1).id()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.id()); + softAssertions.assertThat(actual.get(1).auctionDto()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.auctionDto()); + softAssertions.assertThat(actual.get(1).partnerDto()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.partnerDto()); + softAssertions.assertThat(actual.get(1).lastMessageDto()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.lastMessageDto()); + softAssertions.assertThat(actual.get(1).isChatAvailable()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.isChatAvailable()); }); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/MessageServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/MessageServiceTest.java index b313b22b7..7794679c5 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/MessageServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/MessageServiceTest.java @@ -2,10 +2,10 @@ import com.ddang.ddang.chat.application.dto.ReadMessageDto; import com.ddang.ddang.chat.application.event.MessageNotificationEvent; +import com.ddang.ddang.chat.application.event.UpdateReadMessageLogEvent; import com.ddang.ddang.chat.application.exception.ChatRoomNotFoundException; import com.ddang.ddang.chat.application.exception.MessageNotFoundException; import com.ddang.ddang.chat.application.fixture.MessageServiceFixture; -import com.ddang.ddang.chat.domain.ReadMessageLog; import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.notification.application.NotificationService; @@ -22,12 +22,12 @@ import org.springframework.test.context.event.RecordApplicationEvents; import java.util.List; -import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willDoNothing; @IsolateDatabase @RecordApplicationEvents @@ -44,6 +44,9 @@ class MessageServiceTest extends MessageServiceFixture { @MockBean NotificationService notificationService; + @MockBean + LastReadMessageLogService lastReadMessageLogService; + @Autowired ApplicationEvents events; @@ -107,6 +110,9 @@ class MessageServiceTest extends MessageServiceFixture { @Test void 마지막_조회_메시지가_없는_경우_모든_메시지를_조회한다() { + // given + willDoNothing().given(lastReadMessageLogService).update(any()); + // when final List actual = messageService.readAllByLastMessageId(마지막_조회_메시지_아이디가_없는_메시지_조회용_request); @@ -116,6 +122,9 @@ class MessageServiceTest extends MessageServiceFixture { @Test void 첫_번째_메시지_이후에_생성된_모든_메시지를_조회한다() { + // given + willDoNothing().given(lastReadMessageLogService).update(any()); + // when final List actual = messageService.readAllByLastMessageId(두_번째_메시지부터_모든_메시지_조회용_request); @@ -133,13 +142,13 @@ class MessageServiceTest extends MessageServiceFixture { } @Test - void 메시지를_조회할_경우_마지막으로_읽은_메시지가_업데이트된다() { + void 메시지를_조회할_경우_마지막으로_읽은_메시지_업데이트_이벤트를_호출한다() { // when messageService.readAllByLastMessageId(조회한_마지막_메시지가_5인_메시지_조회용_request); - final Optional readMessageLog = readMessageLogRepository.findBy(발신자.getId(), 메시지가_5개인_채팅방.getId()); + final long actual = events.stream(UpdateReadMessageLogEvent.class).count(); // then - assertThat(readMessageLog.get().getLastReadMessageId()).isEqualTo(메시지가_5개인_채팅방_메시지의_마지막_메시지); + assertThat(actual).isEqualTo(1); } @Test From 0b1e25cf0657c2b0f9297926c51a87e644cf787c Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 17 Oct 2023 23:37:45 +0900 Subject: [PATCH 13/29] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/ddang/user/domain/repository/UserRepository.java | 2 -- .../user/infrastructure/persistence/UserRepositoryImpl.java | 5 ----- 2 files changed, 7 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java index 6f1b7fdfc..bf909cb60 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java @@ -10,8 +10,6 @@ public interface UserRepository { Optional findById(final Long id); - boolean existsById(final Long id); - Optional findByOauthId(final String oauthId); boolean existsByIdAndDeletedIsTrue(final Long id); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java index 5a5e3fac6..1cff56988 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java @@ -23,11 +23,6 @@ public Optional findById(final Long id) { return jpaUserRepository.findById(id); } - @Override - public boolean existsById(final Long id) { - return jpaUserRepository.existsById(id); - } - @Override public Optional findByOauthId(final String oauthId) { return jpaUserRepository.findByOauthId(oauthId); From 066570bc225afac27902afa81c780d10e0cae23c Mon Sep 17 00:00:00 2001 From: swonny Date: Wed, 18 Oct 2023 00:14:11 +0900 Subject: [PATCH 14/29] =?UTF-8?q?test:=20=EC=83=9D=EB=9E=B5=ED=95=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/application/ChatRoomServiceTest.java | 13 +- .../LastReadMessageLogEventListenerTest.java | 55 ++++++ .../LastReadMessageLogServiceTest.java | 56 ++++++ ...astReadMessageLogEventListenerFixture.java | 63 ++++++ .../LastReadMessageLogServiceFixture.java | 183 ++++++++++++++++++ 5 files changed, 365 insertions(+), 5 deletions(-) create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListenerTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogServiceTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogEventListenerFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java index f8d97e30f..3c41795f8 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -146,14 +145,18 @@ class ChatRoomServiceTest extends ChatRoomServiceFixture { softAssertions.assertThat(actual.get(0).id()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.id()); softAssertions.assertThat(actual.get(0).auctionDto()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.auctionDto()); softAssertions.assertThat(actual.get(0).partnerDto()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.partnerDto()); - softAssertions.assertThat(actual.get(0).lastMessageDto()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.lastMessageDto()); - softAssertions.assertThat(actual.get(0).isChatAvailable()).isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.isChatAvailable()); + softAssertions.assertThat(actual.get(0).lastMessageDto()) + .isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.lastMessageDto()); + softAssertions.assertThat(actual.get(0).isChatAvailable()) + .isEqualTo(엔초_채팅_목록의_제이미_엔초_채팅방_정보.isChatAvailable()); softAssertions.assertThat(actual.get(1).id()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.id()); softAssertions.assertThat(actual.get(1).auctionDto()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.auctionDto()); softAssertions.assertThat(actual.get(1).partnerDto()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.partnerDto()); - softAssertions.assertThat(actual.get(1).lastMessageDto()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.lastMessageDto()); - softAssertions.assertThat(actual.get(1).isChatAvailable()).isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.isChatAvailable()); + softAssertions.assertThat(actual.get(1).lastMessageDto()) + .isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.lastMessageDto()); + softAssertions.assertThat(actual.get(1).isChatAvailable()) + .isEqualTo(엔초_채팅_목록의_엔초_지토_채팅방_정보.isChatAvailable()); }); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListenerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListenerTest.java new file mode 100644 index 000000000..fe247ef8c --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListenerTest.java @@ -0,0 +1,55 @@ +package com.ddang.ddang.chat.application; + +import com.ddang.ddang.chat.application.fixture.LastReadMessageLogEventListenerFixture; +import com.ddang.ddang.configuration.IsolateDatabase; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.event.ApplicationEvents; +import org.springframework.test.context.event.RecordApplicationEvents; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.willDoNothing; +import static org.mockito.Mockito.verify; + +@IsolateDatabase +@RecordApplicationEvents +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class LastReadMessageLogEventListenerTest extends LastReadMessageLogEventListenerFixture { + + @Autowired + ApplicationEvents events; + + @Autowired + LastReadMessageLogEventListener lastReadMessageLogEventListener; + + @MockBean + LastReadMessageLogService lastReadMessageLogService; + + @Test + void 이벤트가_호출되면_메시지_로그를_저장한다() { + // given + willDoNothing().given(lastReadMessageLogService).create(any()); + + // when + lastReadMessageLogEventListener.create(생성용_메시지_조회_로그); + + // then + verify(lastReadMessageLogService).create(any()); + } + + @Test + void 이벤트가_호출되면_메시지_로그를_업데이트한다() { + // given + willDoNothing().given(lastReadMessageLogService).update(any()); + + // when + lastReadMessageLogEventListener.update(업데이트용_메시지_조회_로그); + + // then + verify(lastReadMessageLogService).update(any()); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogServiceTest.java new file mode 100644 index 000000000..1e99cfa37 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogServiceTest.java @@ -0,0 +1,56 @@ +package com.ddang.ddang.chat.application; + +import com.ddang.ddang.chat.application.exception.ReadMessageLogNotFoundException; +import com.ddang.ddang.chat.application.fixture.LastReadMessageLogServiceFixture; +import com.ddang.ddang.chat.domain.ReadMessageLog; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; +import com.ddang.ddang.configuration.IsolateDatabase; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.event.RecordApplicationEvents; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@IsolateDatabase +@RecordApplicationEvents +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class LastReadMessageLogServiceTest extends LastReadMessageLogServiceFixture { + + @Autowired + LastReadMessageLogService lastReadMessageLogService; + + @Autowired + ReadMessageLogRepository readMessageLogRepository; + + @Test + void 메시지_로그를_생성한다() { + // given & when + lastReadMessageLogService.create(메시지_로그_생성용_이벤트); + final Optional actual = readMessageLogRepository.findBy(메시지_로그_생성용_발신자_겸_판매자.getId(), 메시지_로그_생성용_채팅방.getId()); + + // then + assertThat(actual).isPresent(); + } + + @Test + void 메시지_로그를_업데이트한다() { + // given & when + lastReadMessageLogService.update(메시지_로그_업데이트용_이벤트); + + // then + assertThat(메시지_로그_업데이트용_이벤트.lastReadMessage()).isEqualTo(메시지_로그_업데이트용_마지막_조회_메시지); + } + + @Test + void 메시지_로그_업데이트시_메시지_조회_로그가_존재하지_않으면_예외가_발생한다() { + // when & then + assertThatThrownBy(() -> lastReadMessageLogService.update(유효하지_않는_메시지_조회_로그)) + .isInstanceOf(ReadMessageLogNotFoundException.class); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogEventListenerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogEventListenerFixture.java new file mode 100644 index 000000000..dc0bd5c35 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogEventListenerFixture.java @@ -0,0 +1,63 @@ +package com.ddang.ddang.chat.application.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.chat.application.event.CreateReadMessageLogEvent; +import com.ddang.ddang.chat.application.event.UpdateReadMessageLogEvent; +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import org.junit.jupiter.api.BeforeEach; + +@SuppressWarnings("NonAsciiCharacters") +public class LastReadMessageLogEventListenerFixture { + + protected CreateReadMessageLogEvent 생성용_메시지_조회_로그; + protected UpdateReadMessageLogEvent 업데이트용_메시지_조회_로그; + protected User 메시지_로그_생성용_발신자_겸_판매자; + protected User 메시지_로그_생성용_입찰자_구매자; + protected User 메시지_로그_업데이트용_발신자_겸_판매자; + protected User 메시지_로그_업데이트용_입찰자; + protected ChatRoom 메시지_로그_생성용_채팅방; + protected Auction 메시지_로그_생성용_경매; + + @BeforeEach + void setUp() { + 메시지_로그_생성용_발신자_겸_판매자 = User.builder() + .name("메시지_로그_생성용_발신자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 메시지_로그_생성용_입찰자_구매자 = User.builder() + .name("메시지_로그_생성용_입찰자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + 메시지_로그_업데이트용_발신자_겸_판매자 = User.builder() + .name("메시지_로그_업데이트용_발신자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + 메시지_로그_업데이트용_입찰자 = User.builder() + .name("메시지_로그_업데이트용_입찰자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12348") + .build(); + + 메시지_로그_생성용_채팅방 = new ChatRoom(메시지_로그_생성용_경매, 메시지_로그_생성용_입찰자_구매자); + + final Message 메시지 = Message.builder() + .chatRoom(메시지_로그_생성용_채팅방) + .writer(메시지_로그_생성용_발신자_겸_판매자) + .contents("메시지") + .build(); + + 업데이트용_메시지_조회_로그 = new UpdateReadMessageLogEvent(메시지_로그_생성용_발신자_겸_판매자, 메시지_로그_생성용_채팅방, 메시지); + 생성용_메시지_조회_로그 = new CreateReadMessageLogEvent(메시지_로그_생성용_채팅방); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java new file mode 100644 index 000000000..94e9335d7 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java @@ -0,0 +1,183 @@ +package com.ddang.ddang.chat.application.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.infrastructure.persistence.BidRepositoryImpl; +import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.chat.application.event.CreateReadMessageLogEvent; +import com.ddang.ddang.chat.application.event.UpdateReadMessageLogEvent; +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.chat.domain.ReadMessageLog; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; +import com.ddang.ddang.chat.infrastructure.persistence.ChatRoomRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.JpaReadMessageLogRepository; +import com.ddang.ddang.chat.infrastructure.persistence.ReadMessageLogRepositoryImpl; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; + +@SuppressWarnings("NonAsciiCharacters") +public class LastReadMessageLogServiceFixture { + + @Autowired + private JpaCategoryRepository categoryRepository; + + private AuctionRepository auctionRepository; + + private UserRepository userRepository; + + private ChatRoomRepository chatRoomRepository; + + private BidRepositoryImpl bidRepository; + + private ReadMessageLogRepository readMessageLogRepository; + + protected CreateReadMessageLogEvent 메시지_로그_생성용_이벤트; + protected UpdateReadMessageLogEvent 메시지_로그_업데이트용_이벤트; + protected UpdateReadMessageLogEvent 유효하지_않는_메시지_조회_로그; + protected User 메시지_로그_생성용_발신자_겸_판매자; + protected User 메시지_로그_생성용_입찰자_구매자; + protected User 메시지_로그_업데이트용_발신자_겸_판매자; + protected User 메시지_로그_업데이트용_입찰자; + protected User 저장되지_않은_사용자; + protected Auction 메시지_로그_생성용_경매; + protected Message 메시지_로그_생성용_마지막_조회_메시지; + protected Message 메시지_로그_업데이트용_마지막_조회_메시지; + protected Auction 메시지_로그_업데이트용_경매; + protected ChatRoom 메시지_로그_생성용_채팅방; + protected ChatRoom 저장되지_않은_채팅방; + + @BeforeEach + void fixtureSetUp( + @Autowired final JPAQueryFactory jpaQueryFactory, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaMessageRepository jpaMessageRepository, + @Autowired final JpaChatRoomRepository jpaChatRoomRepository, + @Autowired final JpaBidRepository jpaBidRepository, + @Autowired final JpaReadMessageLogRepository jpaReadMessageLogRepository + ) { + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); + userRepository = new UserRepositoryImpl(jpaUserRepository); + chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + bidRepository = new BidRepositoryImpl(jpaBidRepository); + readMessageLogRepository = new ReadMessageLogRepositoryImpl(jpaReadMessageLogRepository); + + final Category 전자기기 = new Category("전자기기"); + final Category 전자기기_하위_노트북 = new Category("노트북"); + 전자기기.addSubCategory(전자기기_하위_노트북); + categoryRepository.save(전자기기); + + 메시지_로그_생성용_발신자_겸_판매자 = User.builder() + .name("메시지_로그_생성용_발신자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 메시지_로그_생성용_입찰자_구매자 = User.builder() + .name("메시지_로그_생성용_입찰자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + 메시지_로그_업데이트용_발신자_겸_판매자 = User.builder() + .name("메시지_로그_업데이트용_발신자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + 메시지_로그_업데이트용_입찰자 = User.builder() + .name("메시지_로그_업데이트용_입찰자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12348") + .build(); + 저장되지_않은_사용자 = User.builder() + .name("저장되지_않은_사용자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12349") + .build(); + userRepository.save(메시지_로그_생성용_발신자_겸_판매자); + userRepository.save(메시지_로그_생성용_입찰자_구매자); + userRepository.save(메시지_로그_업데이트용_발신자_겸_판매자); + userRepository.save(메시지_로그_업데이트용_입찰자); + + 메시지_로그_생성용_경매 = Auction.builder() + .title("경매") + .seller(메시지_로그_생성용_발신자_겸_판매자) + .description("description") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(10_000)) + .closingTime(LocalDateTime.now().plusDays(3L)) + .build(); + 메시지_로그_업데이트용_경매 = Auction.builder() + .seller(메시지_로그_업데이트용_발신자_겸_판매자) + .title("메시지_로그_업데이트용_경매") + .description("description") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(10_000)) + .closingTime(LocalDateTime.now().plusDays(3L)) + .build(); + auctionRepository.save(메시지_로그_생성용_경매); + auctionRepository.save(메시지_로그_업데이트용_경매); + + final Bid 메시지_로그_생성용_입찰 = new Bid(메시지_로그_생성용_경매, 메시지_로그_생성용_입찰자_구매자, new BidPrice(15_000)); + final Bid 메시지_로그_업데이트용_입찰 = new Bid(메시지_로그_업데이트용_경매, 메시지_로그_업데이트용_입찰자, new BidPrice(15_000)); + bidRepository.save(메시지_로그_생성용_입찰); + bidRepository.save(메시지_로그_업데이트용_입찰); + 메시지_로그_생성용_경매.updateLastBid(메시지_로그_생성용_입찰); + 메시지_로그_업데이트용_경매.updateLastBid(메시지_로그_업데이트용_입찰); + + 메시지_로그_생성용_채팅방 = new ChatRoom(메시지_로그_생성용_경매, 메시지_로그_생성용_입찰자_구매자); + 저장되지_않은_채팅방 = new ChatRoom(메시지_로그_생성용_경매, 메시지_로그_생성용_입찰자_구매자); + final ChatRoom 메시지_로그_업데이트용_채팅방 = new ChatRoom(메시지_로그_업데이트용_경매, 메시지_로그_업데이트용_발신자_겸_판매자); + chatRoomRepository.save(메시지_로그_생성용_채팅방); + chatRoomRepository.save(메시지_로그_업데이트용_채팅방); + + 메시지_로그_생성용_이벤트 = new CreateReadMessageLogEvent(메시지_로그_생성용_채팅방); + 메시지_로그_업데이트용_이벤트 = new UpdateReadMessageLogEvent(메시지_로그_업데이트용_발신자_겸_판매자, 메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_마지막_조회_메시지); + + 메시지_로그_생성용_마지막_조회_메시지 = Message.builder() + .writer(메시지_로그_생성용_발신자_겸_판매자) + .receiver(메시지_로그_생성용_입찰자_구매자) + .contents("메시지") + .build(); + 메시지_로그_업데이트용_마지막_조회_메시지 = Message.builder() + .writer(메시지_로그_업데이트용_발신자_겸_판매자) + .receiver(메시지_로그_업데이트용_입찰자) + .contents("메시지") + .build(); + final Message 저장되지_않은_메시지 = Message.builder() + .writer(저장되지_않은_사용자) + .contents("저장되지 않은 메시지") + .build(); + 메시지_로그_업데이트용_이벤트 = new UpdateReadMessageLogEvent(메시지_로그_업데이트용_발신자_겸_판매자, 메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_마지막_조회_메시지); + + final ReadMessageLog 메시지_로그_업데이트용_로그 = new ReadMessageLog(메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_발신자_겸_판매자); + readMessageLogRepository.save(메시지_로그_업데이트용_로그); + + 유효하지_않는_메시지_조회_로그 = new UpdateReadMessageLogEvent(저장되지_않은_사용자, 저장되지_않은_채팅방, 저장되지_않은_메시지); + } +} From b4d03e38f944c5810a995a33c4e0a79e3586e624 Mon Sep 17 00:00:00 2001 From: swonny Date: Wed, 18 Oct 2023 00:14:54 +0900 Subject: [PATCH 15/29] =?UTF-8?q?refactor:=20=EC=B1=84=ED=8C=85=EB=B0=A9?= =?UTF-8?q?=EA=B3=BC=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8cascade=20type=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java index f1dd831bc..c741228a4 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/ReadMessageLog.java @@ -28,7 +28,7 @@ public class ReadMessageLog { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.REMOVE}) @JoinColumn(name = "chat_room_id", nullable = false, foreignKey = @ForeignKey(name = "fk_read_message_log_chat_room")) private ChatRoom chatRoom; From e7993c628131b5034806ef3a409c38cac6634bc1 Mon Sep 17 00:00:00 2001 From: swonny Date: Wed, 18 Oct 2023 00:16:36 +0900 Subject: [PATCH 16/29] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ddang/ddang/chat/application/ChatRoomService.java | 1 - .../application/fixture/LastReadMessageLogServiceFixture.java | 1 - 2 files changed, 2 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index 8f8d8e222..095543cef 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -43,7 +43,6 @@ public class ChatRoomService { private final ChatRoomRepository chatRoomRepository; private final ChatRoomAndImageRepository chatRoomAndImageRepository; private final ChatRoomAndMessageAndImageRepository chatRoomAndMessageAndImageRepository; - private final ReadMessageLogRepository readMessageLogRepository; private final UserRepository userRepository; private final AuctionRepository auctionRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java index 94e9335d7..54e02a06a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java @@ -73,7 +73,6 @@ void fixtureSetUp( @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaAuctionRepository jpaAuctionRepository, @Autowired final JpaUserRepository jpaUserRepository, - @Autowired final JpaMessageRepository jpaMessageRepository, @Autowired final JpaChatRoomRepository jpaChatRoomRepository, @Autowired final JpaBidRepository jpaBidRepository, @Autowired final JpaReadMessageLogRepository jpaReadMessageLogRepository From 824d5c2d80d08d6e5f4357c99a88f1c985ee700a Mon Sep 17 00:00:00 2001 From: swonny Date: Wed, 18 Oct 2023 00:25:11 +0900 Subject: [PATCH 17/29] =?UTF-8?q?feat:=20flyway=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A6=BD=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migration/V21__create_read_message_log_tables.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 backend/ddang/src/main/resources/db/migration/V21__create_read_message_log_tables.sql diff --git a/backend/ddang/src/main/resources/db/migration/V21__create_read_message_log_tables.sql b/backend/ddang/src/main/resources/db/migration/V21__create_read_message_log_tables.sql new file mode 100644 index 000000000..3da7ddba0 --- /dev/null +++ b/backend/ddang/src/main/resources/db/migration/V21__create_read_message_log_tables.sql @@ -0,0 +1,10 @@ +create table read_message_log ( + id bigint not null auto_increment, + chat_room_id bigint, + reader_id bigint, + last_read_message_id bigint, + primary key (id) +); + +alter table read_message_log add constraint fk_read_message_log_chat_room foreign key (chat_room_id) references chatRoom (id); +alter table read_message_log add constraint fk_read_message_reader foreign key (reader_id) references users (id); From a1e330917435ceb4995697f1c2a4df69c1336d82 Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 31 Oct 2023 16:52:46 +0900 Subject: [PATCH 18/29] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/chat/application/LastReadMessageLogEventListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java index 1be82cb6d..9a7986df3 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java @@ -10,7 +10,6 @@ @Component @RequiredArgsConstructor -@Slf4j public class LastReadMessageLogEventListener { private final LastReadMessageLogService lastReadMessageLogService; From fbaf37dfde862fe1e4dd81a2b4e288d17a0aff6a Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 31 Oct 2023 16:57:50 +0900 Subject: [PATCH 19/29] =?UTF-8?q?refactor:=20=EA=B0=9C=ED=96=89=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EB=B6=84=EA=B8=B0=EB=AC=B8=20?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EB=A6=BC=EC=9C=BC=EB=A1=9C=20=EB=8C=80?= =?UTF-8?q?=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/ddang/chat/application/ChatRoomService.java | 11 +++-------- .../ddang/ddang/chat/application/MessageService.java | 3 ++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index 095543cef..b346142ae 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -19,7 +19,6 @@ import com.ddang.ddang.chat.domain.repository.ChatRoomAndImageRepository; import com.ddang.ddang.chat.domain.repository.ChatRoomAndMessageAndImageRepository; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; -import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -30,7 +29,6 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.Optional; @Service @Transactional(readOnly = true) @@ -55,12 +53,9 @@ public Long create(final Long userId, final CreateChatRoomDto chatRoomDto) { new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.") ); - final Optional findChatRoom = chatRoomRepository.findChatRoomByAuctionId(findAuction.getId()); - if (findChatRoom.isPresent()) { - return findChatRoom.get().getId(); - } - - return createChatRoom(findUser, findAuction); + return chatRoomRepository.findChatRoomByAuctionId(findAuction.getId()) + .map(ChatRoom::getId) + .orElseGet(() -> createChatRoom(findUser, findAuction)); } private Long createChatRoom(final User findUser, final Auction findAuction) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index c9683ee25..d7189ded5 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -78,8 +78,9 @@ public List readAllByLastMessageId(final ReadMessageRequest requ request.lastMessageId() ); - if (readMessages.size() > 0) { + if (!readMessages.isEmpty()) { final Message lastReadMessage = readMessages.get(readMessages.size() - 1); + messageLogEventPublisher.publishEvent(new UpdateReadMessageLogEvent(reader, chatRoom, lastReadMessage)); } From 35e3b8aff90448522afdb649533fa591bdd7a905 Mon Sep 17 00:00:00 2001 From: swonny Date: Tue, 31 Oct 2023 17:20:54 +0900 Subject: [PATCH 20/29] =?UTF-8?q?feat:=20=EC=95=88=20=EC=9D=BD=EC=9D=80=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EA=B0=9C=EC=88=98=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadChatRoomWithLastMessageResponse.java | 2 + .../src/main/resources/static/docs/docs.html | 100 ++++++++++-------- .../presentation/ChatRoomControllerTest.java | 6 +- 3 files changed, 65 insertions(+), 43 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/presentation/dto/response/ReadChatRoomWithLastMessageResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/presentation/dto/response/ReadChatRoomWithLastMessageResponse.java index 7aa99edc0..4c35179ea 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/presentation/dto/response/ReadChatRoomWithLastMessageResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/presentation/dto/response/ReadChatRoomWithLastMessageResponse.java @@ -7,6 +7,7 @@ public record ReadChatRoomWithLastMessageResponse( ReadChatPartnerResponse chatPartner, ReadAuctionInChatRoomResponse auction, ReadLastMessageResponse lastMessage, + Long unreadMessageCount, boolean isChatAvailable ) { @@ -16,6 +17,7 @@ public static ReadChatRoomWithLastMessageResponse from(final ReadChatRoomWithLas ReadChatPartnerResponse.from(dto.partnerDto()), ReadAuctionInChatRoomResponse.from(dto.auctionDto()), ReadLastMessageResponse.from(dto.lastMessageDto()), + dto.unreadMessageCount(), dto.isChatAvailable() ); } diff --git a/backend/ddang/src/main/resources/static/docs/docs.html b/backend/ddang/src/main/resources/static/docs/docs.html index bf5f56834..9466b1c20 100644 --- a/backend/ddang/src/main/resources/static/docs/docs.html +++ b/backend/ddang/src/main/resources/static/docs/docs.html @@ -913,9 +913,25 @@

요청

} -
-

Unresolved directive in docs.adoc - include::/Users/labtop/intellij/test-ddang/2023-3-ddang/backend/ddang/build/generated-snippets/authentication-controller-test/ouath2-type과_access-token과_refresh-token을_전달하면_탈퇴한다/path-parameters.adoc[]

-
+ + ++++ + + + + + + + + + + + + +
Table 2. /oauth2/withdrawal/{oauth2Type}
ParameterDescription

oauth2Type

소셜 로그인을 할 서비스 선택(kakao로 고정)

@@ -1278,7 +1294,7 @@

요청

- +@@ -1357,7 +1373,7 @@

요청

Table 2. /regions/{firstId}Table 3. /regions/{firstId}
- +@@ -1453,7 +1469,7 @@

요청

Content-Disposition: form-data; name=request; filename=request Content-Type: application/json -{"title":"제목","description":"내용","bidUnit":1000,"startPrice":1000,"closingTime":"2023-10-18T21:12:06.450773","subCategoryId":2,"thirdRegionIds":[3]} +{"title":"제목","description":"내용","bidUnit":1000,"startPrice":1000,"closingTime":"2023-11-03T16:59:34.062594","subCategoryId":2,"thirdRegionIds":[3]} --6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm-- @@ -2002,7 +2018,7 @@

요청

Table 3. /regions/{firstId}/{secondId}Table 4. /regions/{firstId}/{secondId}
- +@@ -2060,8 +2076,8 @@

응답

"lastBidPrice" : null, "status" : "UNBIDDEN", "bidUnit" : 1000, - "registerTime" : "2023-10-15T21:12:06", - "closingTime" : "2023-10-15T21:12:06", + "registerTime" : "2023-10-31T16:59:34", + "closingTime" : "2023-10-31T16:59:34", "directRegions" : [ { "first" : "서울특별시", "second" : "강서구", @@ -2254,7 +2270,7 @@

요청

Table 4. /auctions/{auctionId}Table 5. /auctions/{auctionId}
- +@@ -2405,7 +2421,7 @@

요청

Table 5. /auctions/{auctionId}Table 6. /auctions/{auctionId}
- +@@ -2533,7 +2549,7 @@

요청

Table 6. /questions/{questionId}Table 7. /questions/{questionId}
- +@@ -2589,7 +2605,7 @@

응답

"name" : "질문자", "image" : "http://localhost:8080/users/images/1" }, - "createdTime" : "2023-10-15T21:12:06", + "createdTime" : "2023-10-31T16:59:34", "content" : "질문1", "isQuestioner" : false }, @@ -2600,7 +2616,7 @@

응답

"name" : "판매자", "image" : "http://localhost:8080/users/images/2" }, - "createdTime" : "2023-10-15T21:12:06", + "createdTime" : "2023-10-31T16:59:34", "content" : "답변1" } }, { @@ -2611,7 +2627,7 @@

응답

"name" : "질문자", "image" : "http://localhost:8080/users/images/1" }, - "createdTime" : "2023-10-15T21:12:06", + "createdTime" : "2023-10-31T16:59:34", "content" : "질문2", "isQuestioner" : false }, @@ -2622,7 +2638,7 @@

응답

"name" : "판매자", "image" : "http://localhost:8080/users/images/2" }, - "createdTime" : "2023-10-15T21:12:06", + "createdTime" : "2023-10-31T16:59:34", "content" : "답변1" } } ] @@ -2835,12 +2851,12 @@

응답

"name" : "사용자1", "profileImage" : "http://localhost:8080/users/images/1", "price" : 10000, - "bidTime" : "2023-10-15T21:12:13" + "bidTime" : "2023-10-31T16:59:40" }, { "name" : "사용자2", "profileImage" : "http://localhost:8080/users/images/2", "price" : 12000, - "bidTime" : "2023-10-15T21:12:13" + "bidTime" : "2023-10-31T16:59:40" } ] @@ -3034,7 +3050,7 @@

응답

"price" : 10000 }, "lastMessage" : { - "createdAt" : "2023-10-15T21:12:16", + "createdAt" : "2023-10-31T16:59:45", "contents" : "메시지1" }, "isChatAvailable" : true @@ -3052,7 +3068,7 @@

응답

"price" : 20000 }, "lastMessage" : { - "createdAt" : "2023-10-15T21:12:16", + "createdAt" : "2023-10-31T16:59:45", "contents" : "메시지2" }, "isChatAvailable" : true @@ -3164,7 +3180,7 @@

요청

Table 7. /questions/answers/{answerId}Table 8. /questions/answers/{answerId}
- +@@ -3315,7 +3331,7 @@

요청

Table 8. /chattings/{chatRoomId}Table 9. /chattings/{chatRoomId}
- +@@ -3426,7 +3442,7 @@

요청

Table 9. /chattings/{chatRoomId}/messagesTable 10. /chattings/{chatRoomId}/messages
- +@@ -3490,7 +3506,7 @@

응답

[ { "id" : 1, - "createdAt" : "2023-10-15T21:12:16", + "createdAt" : "2023-10-31T16:59:44", "isMyMessage" : true, "contents" : "메시지내용" } ] @@ -3640,7 +3656,7 @@

응답

"id" : 2, "name" : "회원1" }, - "createdTime" : "2023-10-15T21:12:26", + "createdTime" : "2023-10-31T16:59:54", "auction" : { "id" : 1, "title" : "제목" @@ -3652,7 +3668,7 @@

응답

"id" : 3, "name" : "회원2" }, - "createdTime" : "2023-10-15T21:12:26", + "createdTime" : "2023-10-31T16:59:54", "auction" : { "id" : 1, "title" : "제목" @@ -3664,7 +3680,7 @@

응답

"id" : 4, "name" : "회원3" }, - "createdTime" : "2023-10-15T21:12:26", + "createdTime" : "2023-10-31T16:59:54", "auction" : { "id" : 1, "title" : "제목" @@ -3828,7 +3844,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T21:12:27", + "createdTime" : "2023-10-31T16:59:54", "chatRoom" : { "id" : 1 }, @@ -3839,7 +3855,7 @@

응답

"id" : 3, "name" : "구매자2" }, - "createdTime" : "2023-10-15T21:12:27", + "createdTime" : "2023-10-31T16:59:54", "chatRoom" : { "id" : 1 }, @@ -3850,7 +3866,7 @@

응답

"id" : 3, "name" : "구매자2" }, - "createdTime" : "2023-10-15T21:12:27", + "createdTime" : "2023-10-31T16:59:54", "chatRoom" : { "id" : 1 }, @@ -4014,7 +4030,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T21:12:27", + "createdTime" : "2023-10-31T16:59:55", "question" : { "id" : 1 }, @@ -4025,7 +4041,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T21:12:27", + "createdTime" : "2023-10-31T16:59:55", "question" : { "id" : 2 }, @@ -4036,7 +4052,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T21:12:27", + "createdTime" : "2023-10-31T16:59:55", "question" : { "id" : 3 }, @@ -4200,7 +4216,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T21:12:27", + "createdTime" : "2023-10-31T16:59:55", "answer" : { "id" : 1 }, @@ -4211,7 +4227,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T21:12:27", + "createdTime" : "2023-10-31T16:59:55", "answer" : { "id" : 2 }, @@ -4222,7 +4238,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T21:12:27", + "createdTime" : "2023-10-31T16:59:55", "answer" : { "id" : 3 }, @@ -4452,7 +4468,7 @@

요청

Table 10. /chattings/{chatRoomId}/messagesTable 11. /chattings/{chatRoomId}/messages
- +@@ -4523,7 +4539,7 @@

요청

Table 11. /reviews/{reviewId}Table 12. /reviews/{reviewId}
- +@@ -4558,7 +4574,7 @@

응답

}, "content" : "친절하다.", "score" : 5.0, - "createdTime" : "2023-10-15T21:12:29" + "createdTime" : "2023-10-31T16:59:56" }, { "id" : 2, "writer" : { @@ -4568,7 +4584,7 @@

응답

}, "content" : "친절하다.", "score" : 5.0, - "createdTime" : "2023-10-15T21:12:29" + "createdTime" : "2023-10-31T16:59:56" } ] @@ -4642,7 +4658,7 @@

요청

Table 12. /reviews/users/{userId}Table 13. /reviews/users/{userId}
- +@@ -4726,7 +4742,7 @@

응답

diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/presentation/ChatRoomControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/presentation/ChatRoomControllerTest.java index 76b29dda0..d0f948c66 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/presentation/ChatRoomControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/presentation/ChatRoomControllerTest.java @@ -247,13 +247,15 @@ void setUp() { .title())), jsonPath("$.[0].lastMessage.contents", is(조회용_채팅방1.lastMessageDto() .contents())), + jsonPath("$.[0].unreadMessageCount", is(조회용_채팅방1.unreadMessageCount()), Long.class), jsonPath("$.[1].id", is(조회용_채팅방2.id()), Long.class), jsonPath("$.[1].chatPartner.name", is(조회용_채팅방2.partnerDto() .name())), jsonPath("$.[1].auction.title", is(조회용_채팅방2.auctionDto() .title())), jsonPath("$.[1].lastMessage.contents", is(조회용_채팅방2.lastMessageDto() - .contents())) + .contents())), + jsonPath("$.[1].unreadMessageCount", is(조회용_채팅방1.unreadMessageCount()), Long.class) ); readAllParticipatingChatRooms_문서화(resultActions); } @@ -539,6 +541,8 @@ void setUp() { .description("메시지를 보낸 시간"), fieldWithPath("[].lastMessage.contents").type(JsonFieldType.STRING) .description("메시지 내용"), + fieldWithPath("[].unreadMessageCount").type(JsonFieldType.NUMBER) + .description("안 읽은 메시지 개수"), fieldWithPath("[].isChatAvailable").type(JsonFieldType.BOOLEAN) .description("채팅 가능 여부") ) From 83aa31c7c5916b9df4f84c2ea69b9c7cd06bfc39 Mon Sep 17 00:00:00 2001 From: swonny Date: Wed, 1 Nov 2023 16:00:20 +0900 Subject: [PATCH 21/29] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=95=84=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ddang/ddang/chat/application/ChatRoomServiceTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java index 3c41795f8..c77118c77 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java @@ -38,9 +38,6 @@ class ChatRoomServiceTest extends ChatRoomServiceFixture { @Autowired ChatRoomService chatRoomService; - @Autowired - MessageService messageService; - @Autowired ReadMessageLogRepository readMessageLogRepository; From 688d8e2747fe38dc8d50528c60c068926aa3c777 Mon Sep 17 00:00:00 2001 From: swonny Date: Wed, 1 Nov 2023 16:25:23 +0900 Subject: [PATCH 22/29] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20join=EC=9D=B4=20=EB=B0=9C=EC=83=9D=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=BF=BC=EB=A6=AC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/ddang/chat/application/ChatRoomService.java | 3 +-- .../ddang/chat/domain/repository/ChatRoomRepository.java | 2 -- .../persistence/ChatRoomRepositoryImpl.java | 5 ----- .../persistence/JpaChatRoomRepository.java | 9 --------- 4 files changed, 1 insertion(+), 18 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index b346142ae..8e91c6c0a 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -53,8 +53,7 @@ public Long create(final Long userId, final CreateChatRoomDto chatRoomDto) { new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.") ); - return chatRoomRepository.findChatRoomByAuctionId(findAuction.getId()) - .map(ChatRoom::getId) + return chatRoomRepository.findChatRoomIdByAuctionId(findAuction.getId()) .orElseGet(() -> createChatRoom(findUser, findAuction)); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java index d06351532..3935ababc 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java @@ -10,8 +10,6 @@ public interface ChatRoomRepository { Optional findById(final Long id); - Optional findChatRoomByAuctionId(final Long auctionId); - Optional findChatRoomIdByAuctionId(final Long auctionId); boolean existsByAuctionId(final Long auctionId); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java index 78dc8754c..a2d88ceb8 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java @@ -23,11 +23,6 @@ public Optional findById(final Long id) { return jpaChatRoomRepository.findById(id); } - @Override - public Optional findChatRoomByAuctionId(final Long auctionId) { - return jpaChatRoomRepository.findChatRoomByAuctionId(auctionId); - } - @Override public Optional findChatRoomIdByAuctionId(final Long auctionId) { return jpaChatRoomRepository.findChatRoomIdByAuctionId(auctionId); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java index def135423..639a831ca 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java @@ -8,15 +8,6 @@ public interface JpaChatRoomRepository extends JpaRepository { - @Query(""" - SELECT c - FROM ChatRoom c - JOIN FETCH c.buyer - JOIN FETCH c.auction.seller - WHERE c.auction.id = :auctionId - """) - Optional findChatRoomByAuctionId(final Long auctionId); - @Query(""" SELECT c.id FROM ChatRoom c From 591ccd527592224930b337cb28a62169144fa488 Mon Sep 17 00:00:00 2001 From: swonny Date: Wed, 1 Nov 2023 16:59:47 +0900 Subject: [PATCH 23/29] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20import=EB=AC=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/chat/application/LastReadMessageLogEventListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java index 9a7986df3..7bb2401b0 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java @@ -3,7 +3,6 @@ import com.ddang.ddang.chat.application.event.CreateReadMessageLogEvent; import com.ddang.ddang.chat.application.event.UpdateReadMessageLogEvent; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; From 3019893128f875b9029f28fe0af99562fa43568b Mon Sep 17 00:00:00 2001 From: swonny Date: Fri, 3 Nov 2023 10:16:52 +0900 Subject: [PATCH 24/29] =?UTF-8?q?refactor:=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=20=EC=A0=84=EC=86=A1=EA=B3=BC=20=EC=9D=BD=EC=9D=8C=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=98=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LastReadMessageLogEventListener.java | 26 +++++++++++++----- .../chat/application/MessageService.java | 2 -- .../chat/application/ChatRoomServiceTest.java | 18 ------------- .../LastReadMessageLogServiceTest.java | 27 ++++++++++++++++--- .../LastReadMessageLogServiceFixture.java | 8 +++--- 5 files changed, 46 insertions(+), 35 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java index 7bb2401b0..5c67a1089 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListener.java @@ -2,26 +2,38 @@ import com.ddang.ddang.chat.application.event.CreateReadMessageLogEvent; import com.ddang.ddang.chat.application.event.UpdateReadMessageLogEvent; +import com.ddang.ddang.chat.application.exception.ReadMessageLogNotFoundException; import lombok.RequiredArgsConstructor; -import org.springframework.context.event.EventListener; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.event.TransactionalEventListener; +@Slf4j @Component @RequiredArgsConstructor public class LastReadMessageLogEventListener { private final LastReadMessageLogService lastReadMessageLogService; - @EventListener - @Transactional + @TransactionalEventListener + @Transactional(propagation = Propagation.REQUIRES_NEW) public void create(final CreateReadMessageLogEvent createReadMessageLogEvent) { - lastReadMessageLogService.create(createReadMessageLogEvent); + try { + lastReadMessageLogService.create(createReadMessageLogEvent); + } catch (final IllegalArgumentException ex) { + log.error("exception type : {}, ", ex.getClass().getSimpleName(), ex); + } } - @EventListener - @Transactional + @TransactionalEventListener + @Transactional(propagation = Propagation.REQUIRES_NEW) public void update(final UpdateReadMessageLogEvent updateReadMessageLogEvent) { - lastReadMessageLogService.update(updateReadMessageLogEvent); + try { + lastReadMessageLogService.update(updateReadMessageLogEvent); + } catch (final ReadMessageLogNotFoundException ex) { + log.error("exception type : {}, ", ex.getClass().getSimpleName(), ex); + } } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index d7189ded5..b96430cec 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -16,7 +16,6 @@ import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -26,7 +25,6 @@ @Service @Transactional(readOnly = true) @RequiredArgsConstructor -@Slf4j public class MessageService { private final ApplicationEventPublisher messageLogEventPublisher; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java index c77118c77..eeb42b1fb 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java @@ -10,7 +10,6 @@ import com.ddang.ddang.chat.application.exception.InvalidAuctionToChatException; import com.ddang.ddang.chat.application.exception.InvalidUserToChat; import com.ddang.ddang.chat.application.fixture.ChatRoomServiceFixture; -import com.ddang.ddang.chat.domain.ReadMessageLog; import com.ddang.ddang.chat.domain.repository.MessageRepository; import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.configuration.IsolateDatabase; @@ -24,7 +23,6 @@ import org.springframework.test.context.event.RecordApplicationEvents; import java.util.List; -import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -47,22 +45,6 @@ class ChatRoomServiceTest extends ChatRoomServiceFixture { @Autowired ApplicationEvents events; - @Test - void 채팅방_생성시_채팅_참여자에_대한_로그를_생성한다() { - // given - final Long createdChatRoomId = chatRoomService.create(채팅방을_생성하는_메리.getId(), 메리가_생성하려는_채팅방); - - // when - final Optional actual_메리 = readMessageLogRepository.findBy(채팅방을_생성하는_메리.getId(), createdChatRoomId); - final Optional actual_지토 = readMessageLogRepository.findBy(메리_경매_낙찰자_지토.getId(), createdChatRoomId); - - // then - SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual_메리).isPresent(); - softAssertions.assertThat(actual_지토).isPresent(); - }); - } - @Test void 채팅방을_생성한다() { // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogServiceTest.java index 1e99cfa37..5512fabe3 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogServiceTest.java @@ -5,6 +5,7 @@ import com.ddang.ddang.chat.domain.ReadMessageLog; import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.configuration.IsolateDatabase; +import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -13,7 +14,6 @@ import java.util.Optional; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @IsolateDatabase @@ -32,10 +32,14 @@ class LastReadMessageLogServiceTest extends LastReadMessageLogServiceFixture { void 메시지_로그를_생성한다() { // given & when lastReadMessageLogService.create(메시지_로그_생성용_이벤트); - final Optional actual = readMessageLogRepository.findBy(메시지_로그_생성용_발신자_겸_판매자.getId(), 메시지_로그_생성용_채팅방.getId()); + final Optional actual_판매자 = readMessageLogRepository.findBy(메시지_로그_생성용_발신자_겸_판매자.getId(), 메시지_로그_생성용_채팅방.getId()); + final Optional actual_구매자 = readMessageLogRepository.findBy(메시지_로그_생성용_입찰자_구매자.getId(), 메시지_로그_생성용_채팅방.getId()); // then - assertThat(actual).isPresent(); + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual_판매자).isPresent(); + softAssertions.assertThat(actual_구매자).isPresent(); + }); } @Test @@ -43,8 +47,23 @@ class LastReadMessageLogServiceTest extends LastReadMessageLogServiceFixture { // given & when lastReadMessageLogService.update(메시지_로그_업데이트용_이벤트); + final Optional actual_발신자 = readMessageLogRepository.findBy( + 메시지_로그_업데이트용_발신자_겸_판매자.getId(), + 메시지_로그_업데이트용_채팅방.getId() + ); + final Optional actual_입찰자 = readMessageLogRepository.findBy( + 메시지_로그_업데이트용_입찰자.getId(), + 메시지_로그_업데이트용_채팅방.getId() + ); + // then - assertThat(메시지_로그_업데이트용_이벤트.lastReadMessage()).isEqualTo(메시지_로그_업데이트용_마지막_조회_메시지); + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual_발신자).isPresent(); + softAssertions.assertThat(actual_발신자.get().getLastReadMessageId()) + .isEqualTo(메시지_로그_업데이트용_마지막_조회_메시지.getId()); + softAssertions.assertThat(actual_입찰자.get().getLastReadMessageId()) + .isNotEqualTo(메시지_로그_업데이트용_마지막_조회_메시지.getId()); + }); } @Test diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java index 54e02a06a..ac7fb7928 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java @@ -22,7 +22,6 @@ import com.ddang.ddang.chat.domain.repository.ReadMessageLogRepository; import com.ddang.ddang.chat.infrastructure.persistence.ChatRoomRepositoryImpl; import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; -import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; import com.ddang.ddang.chat.infrastructure.persistence.JpaReadMessageLogRepository; import com.ddang.ddang.chat.infrastructure.persistence.ReadMessageLogRepositoryImpl; import com.ddang.ddang.image.domain.ProfileImage; @@ -67,6 +66,7 @@ public class LastReadMessageLogServiceFixture { protected Auction 메시지_로그_업데이트용_경매; protected ChatRoom 메시지_로그_생성용_채팅방; protected ChatRoom 저장되지_않은_채팅방; + protected ChatRoom 메시지_로그_업데이트용_채팅방; @BeforeEach void fixtureSetUp( @@ -151,12 +151,11 @@ void fixtureSetUp( 메시지_로그_생성용_채팅방 = new ChatRoom(메시지_로그_생성용_경매, 메시지_로그_생성용_입찰자_구매자); 저장되지_않은_채팅방 = new ChatRoom(메시지_로그_생성용_경매, 메시지_로그_생성용_입찰자_구매자); - final ChatRoom 메시지_로그_업데이트용_채팅방 = new ChatRoom(메시지_로그_업데이트용_경매, 메시지_로그_업데이트용_발신자_겸_판매자); + 메시지_로그_업데이트용_채팅방 = new ChatRoom(메시지_로그_업데이트용_경매, 메시지_로그_업데이트용_발신자_겸_판매자); chatRoomRepository.save(메시지_로그_생성용_채팅방); chatRoomRepository.save(메시지_로그_업데이트용_채팅방); 메시지_로그_생성용_이벤트 = new CreateReadMessageLogEvent(메시지_로그_생성용_채팅방); - 메시지_로그_업데이트용_이벤트 = new UpdateReadMessageLogEvent(메시지_로그_업데이트용_발신자_겸_판매자, 메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_마지막_조회_메시지); 메시지_로그_생성용_마지막_조회_메시지 = Message.builder() .writer(메시지_로그_생성용_발신자_겸_판매자) @@ -172,11 +171,12 @@ void fixtureSetUp( .writer(저장되지_않은_사용자) .contents("저장되지 않은 메시지") .build(); - 메시지_로그_업데이트용_이벤트 = new UpdateReadMessageLogEvent(메시지_로그_업데이트용_발신자_겸_판매자, 메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_마지막_조회_메시지); final ReadMessageLog 메시지_로그_업데이트용_로그 = new ReadMessageLog(메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_발신자_겸_판매자); readMessageLogRepository.save(메시지_로그_업데이트용_로그); + 메시지_로그_업데이트용_이벤트 = new UpdateReadMessageLogEvent(메시지_로그_업데이트용_발신자_겸_판매자, 메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_마지막_조회_메시지); + 유효하지_않는_메시지_조회_로그 = new UpdateReadMessageLogEvent(저장되지_않은_사용자, 저장되지_않은_채팅방, 저장되지_않은_메시지); } } From 3bec36dbe1c339a391d9b12537c7d95b8ae7395b Mon Sep 17 00:00:00 2001 From: swonny Date: Fri, 3 Nov 2023 21:21:50 +0900 Subject: [PATCH 25/29] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C,=20=EC=9E=90=EB=8F=99=20=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/ddang/chat/application/MessageService.java | 1 - .../application/fixture/MessageServiceFixture.java | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index b96430cec..9d9045ecb 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -58,7 +58,6 @@ public Long create(final CreateMessageDto dto, final String profileImageAbsolute return persistMessage.getId(); } - @Transactional public List readAllByLastMessageId(final ReadMessageRequest request) { final User reader = userRepository.findById(request.messageReaderId()) .orElseThrow(() -> new UserNotFoundException("지정한 아이디에 대한 사용자를 찾을 수 없습니다.")); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java index bd7af5daf..01765bf70 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java @@ -77,11 +77,11 @@ void setUp() { auctionRepository.save(경매); 발신자 = User.builder() - .name("발신자") - .profileImage(new ProfileImage("upload.png", "store.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); + .name("발신자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); final User 수신자 = User.builder() .name("수신자") .profileImage(new ProfileImage("upload.png", "store.png")) From 71022871252e4c52de785625378329f9ed101e97 Mon Sep 17 00:00:00 2001 From: swonny Date: Fri, 3 Nov 2023 21:51:55 +0900 Subject: [PATCH 26/29] =?UTF-8?q?test:=20=EC=98=88=EC=99=B8=20=EC=BC=80?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LastReadMessageLogEventListenerTest.java | 21 +++++++++++++++++++ .../LastReadMessageLogServiceFixture.java | 6 ++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListenerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListenerTest.java index fe247ef8c..5e0041468 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListenerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/LastReadMessageLogEventListenerTest.java @@ -1,5 +1,6 @@ package com.ddang.ddang.chat.application; +import com.ddang.ddang.chat.application.exception.ReadMessageLogNotFoundException; import com.ddang.ddang.chat.application.fixture.LastReadMessageLogEventListenerFixture; import com.ddang.ddang.configuration.IsolateDatabase; import org.junit.jupiter.api.DisplayNameGeneration; @@ -10,8 +11,10 @@ import org.springframework.test.context.event.ApplicationEvents; import org.springframework.test.context.event.RecordApplicationEvents; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.willDoNothing; +import static org.mockito.BDDMockito.willThrow; import static org.mockito.Mockito.verify; @IsolateDatabase @@ -41,6 +44,15 @@ class LastReadMessageLogEventListenerTest extends LastReadMessageLogEventListene verify(lastReadMessageLogService).create(any()); } + @Test + void 메시지_로그_저장에_실패한_경우_예외가_발생하지_않는다() { + // given + willThrow(IllegalArgumentException.class).given(lastReadMessageLogService).create(any()); + + // when & then + assertDoesNotThrow(() -> lastReadMessageLogEventListener.create(생성용_메시지_조회_로그)); + } + @Test void 이벤트가_호출되면_메시지_로그를_업데이트한다() { // given @@ -52,4 +64,13 @@ class LastReadMessageLogEventListenerTest extends LastReadMessageLogEventListene // then verify(lastReadMessageLogService).update(any()); } + + @Test + void 메시지_로그_업데이트에_실패한_경우_예외가_발생하지_않는다() { + // given + willThrow(ReadMessageLogNotFoundException.class).given(lastReadMessageLogService).update(any()); + + // when & then + assertDoesNotThrow(() -> lastReadMessageLogEventListener.update(업데이트용_메시지_조회_로그)); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java index ac7fb7928..928d695a7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java @@ -172,8 +172,10 @@ void fixtureSetUp( .contents("저장되지 않은 메시지") .build(); - final ReadMessageLog 메시지_로그_업데이트용_로그 = new ReadMessageLog(메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_발신자_겸_판매자); - readMessageLogRepository.save(메시지_로그_업데이트용_로그); + final ReadMessageLog 메시지_로그_업데이트용_로그_판매자 = new ReadMessageLog(메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_발신자_겸_판매자); + final ReadMessageLog 메시지_로그_업데이트용_로그_구매자 = new ReadMessageLog(메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_입찰자); + readMessageLogRepository.save(메시지_로그_업데이트용_로그_판매자); + readMessageLogRepository.save(메시지_로그_업데이트용_로그_구매자); 메시지_로그_업데이트용_이벤트 = new UpdateReadMessageLogEvent(메시지_로그_업데이트용_발신자_겸_판매자, 메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_마지막_조회_메시지); From dbad4b35d7297390abb7417bc8708c0bba6a8338 Mon Sep 17 00:00:00 2001 From: swonny Date: Sat, 4 Nov 2023 18:35:00 +0900 Subject: [PATCH 27/29] =?UTF-8?q?refactor:=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20=EC=A0=81=EC=A0=88=ED=95=9C=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=EB=AA=85=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ddang/chat/application/LastReadMessageLogService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java index 557d705e0..6c1ee8385 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java @@ -31,14 +31,14 @@ public void create(final CreateReadMessageLogEvent createReadMessageLogEvent) { } @Transactional - public void update(final UpdateReadMessageLogEvent createReadMessageLogEvent) { - final User reader = createReadMessageLogEvent.reader(); - final ChatRoom chatRoom = createReadMessageLogEvent.chatRoom(); + public void update(final UpdateReadMessageLogEvent updateReadMessageLogEvent) { + final User reader = updateReadMessageLogEvent.reader(); + final ChatRoom chatRoom = updateReadMessageLogEvent.chatRoom(); final ReadMessageLog messageLog = readMessageLogRepository.findBy(reader.getId(), chatRoom.getId()) .orElseThrow(() -> new ReadMessageLogNotFoundException( "메시지 조회 로그가 존재하지 않습니다." )); - messageLog.updateLastReadMessage(createReadMessageLogEvent.lastReadMessage().getId()); + messageLog.updateLastReadMessage(updateReadMessageLogEvent.lastReadMessage().getId()); } } From 461d34dfe7be5724d300b9af18cc7569c02516e4 Mon Sep 17 00:00:00 2001 From: swonny Date: Sat, 4 Nov 2023 18:49:02 +0900 Subject: [PATCH 28/29] =?UTF-8?q?refactor:=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=A0=80=EC=9E=A5=20=EC=8B=9C=20=EC=97=AC?= =?UTF-8?q?=EB=9F=AC=20=EA=B0=9C=20=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/application/LastReadMessageLogService.java | 6 ++++-- .../chat/domain/repository/ReadMessageLogRepository.java | 5 +++-- .../persistence/ReadMessageLogRepositoryImpl.java | 9 +++++---- .../fixture/LastReadMessageLogServiceFixture.java | 4 ++-- ...QuerydslChatRoomAndMessageAndImageRepositoryTest.java | 3 +-- .../persistence/ReadMessageLogRepositoryImplTest.java | 3 ++- .../fixture/ReadMessageLogRepositoryFixture.java | 2 +- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java index 6c1ee8385..abba0d301 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/LastReadMessageLogService.java @@ -11,6 +11,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -26,8 +28,7 @@ public void create(final CreateReadMessageLogEvent createReadMessageLogEvent) { final ReadMessageLog buyerReadMessageLog = new ReadMessageLog(chatRoom, buyer); final ReadMessageLog sellerReadMessageLog = new ReadMessageLog(chatRoom, seller); - readMessageLogRepository.save(buyerReadMessageLog); - readMessageLogRepository.save(sellerReadMessageLog); + readMessageLogRepository.saveAll(List.of(buyerReadMessageLog, sellerReadMessageLog)); } @Transactional @@ -39,6 +40,7 @@ public void update(final UpdateReadMessageLogEvent updateReadMessageLogEvent) { new ReadMessageLogNotFoundException( "메시지 조회 로그가 존재하지 않습니다." )); + messageLog.updateLastReadMessage(updateReadMessageLogEvent.lastReadMessage().getId()); } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java index 7336fa340..0da187e3a 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ReadMessageLogRepository.java @@ -2,11 +2,12 @@ import com.ddang.ddang.chat.domain.ReadMessageLog; +import java.util.List; import java.util.Optional; public interface ReadMessageLogRepository { - ReadMessageLog save(final ReadMessageLog readMessageLog); - Optional findBy(final Long readerId, final Long chatRoomId); + + List saveAll(List readMessageLogs); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java index bab34022f..dceecf3ed 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImpl.java @@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @@ -14,12 +15,12 @@ public class ReadMessageLogRepositoryImpl implements ReadMessageLogRepository { private final JpaReadMessageLogRepository jpaReadMessageLogRepository; @Override - public ReadMessageLog save(final ReadMessageLog readMessageLog) { - return jpaReadMessageLogRepository.save(readMessageLog); + public Optional findBy(final Long readerId, final Long chatRoomId) { + return jpaReadMessageLogRepository.findLastReadMessageByUserIdAndChatRoomId(readerId, chatRoomId); } @Override - public Optional findBy(final Long readerId, final Long chatRoomId) { - return jpaReadMessageLogRepository.findLastReadMessageByUserIdAndChatRoomId(readerId, chatRoomId); + public List saveAll(final List readMessageLogs) { + return jpaReadMessageLogRepository.saveAll(readMessageLogs); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java index 928d695a7..737969fd0 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/LastReadMessageLogServiceFixture.java @@ -35,6 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired; import java.time.LocalDateTime; +import java.util.List; @SuppressWarnings("NonAsciiCharacters") public class LastReadMessageLogServiceFixture { @@ -174,8 +175,7 @@ void fixtureSetUp( final ReadMessageLog 메시지_로그_업데이트용_로그_판매자 = new ReadMessageLog(메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_발신자_겸_판매자); final ReadMessageLog 메시지_로그_업데이트용_로그_구매자 = new ReadMessageLog(메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_입찰자); - readMessageLogRepository.save(메시지_로그_업데이트용_로그_판매자); - readMessageLogRepository.save(메시지_로그_업데이트용_로그_구매자); + readMessageLogRepository.saveAll(List.of(메시지_로그_업데이트용_로그_판매자, 메시지_로그_업데이트용_로그_구매자)); 메시지_로그_업데이트용_이벤트 = new UpdateReadMessageLogEvent(메시지_로그_업데이트용_발신자_겸_판매자, 메시지_로그_업데이트용_채팅방, 메시지_로그_업데이트용_마지막_조회_메시지); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java index 89ead8823..fc55b97c7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java @@ -45,8 +45,7 @@ void setUp( @Test void 사용자가_읽지_않은_메시지_개수를_반환한다() { // given - readMessageLogRepository.save(new ReadMessageLog(메리_엔초_채팅방, 엔초)); - readMessageLogRepository.save(new ReadMessageLog(메리_엔초_채팅방, 메리)); + readMessageLogRepository.saveAll(List.of(new ReadMessageLog(메리_엔초_채팅방, 메리), new ReadMessageLog(메리_엔초_채팅방, 엔초))); // when messageRepository.save(메리가_엔초에게_3시에_보낸_쪽지1); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java index 758d1c064..ad254efd8 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ReadMessageLogRepositoryImplTest.java @@ -14,6 +14,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; +import java.util.List; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @@ -34,7 +35,7 @@ void setUp(@Autowired final JpaReadMessageLogRepository jpaReadMessageLogReposit @Test void 마지막_읽은_메시지를_저장한다() { // given - final ReadMessageLog actual = readMessageLogRepository.save(다섯_번째_메시지까지_읽은_메시지_로그); + final ReadMessageLog actual = readMessageLogRepository.saveAll(List.of(다섯_번째_메시지까지_읽은_메시지_로그)).get(0); // then assertThat(actual.getId()).isPositive(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java index 71a594bad..02c48e537 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ReadMessageLogRepositoryFixture.java @@ -144,6 +144,6 @@ void fixtureSetUp( final ReadMessageLog 메리_엔초_채팅방의_메리_메시지_조회_로그 = new ReadMessageLog(메리_엔초_채팅방, 메리); 메리_엔초_채팅방의_메리_메시지_조회_로그.updateLastReadMessage(다섯_번째_메시지.getId()); - readMessageLogRepository.save(메리_엔초_채팅방의_메리_메시지_조회_로그); + readMessageLogRepository.saveAll(List.of(메리_엔초_채팅방의_메리_메시지_조회_로그)); } } From c299d27e256c5deeee9f3ecb7e8980b3725bde08 Mon Sep 17 00:00:00 2001 From: swonny Date: Sun, 5 Nov 2023 15:05:11 +0900 Subject: [PATCH 29/29] =?UTF-8?q?chore:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20fl?= =?UTF-8?q?yway=20=EC=8A=A4=ED=81=AC=EB=A6=BC=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/migration/V21__create_read_message_log_tables.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ddang/src/main/resources/db/migration/V21__create_read_message_log_tables.sql b/backend/ddang/src/main/resources/db/migration/V21__create_read_message_log_tables.sql index 3da7ddba0..0cc6063d2 100644 --- a/backend/ddang/src/main/resources/db/migration/V21__create_read_message_log_tables.sql +++ b/backend/ddang/src/main/resources/db/migration/V21__create_read_message_log_tables.sql @@ -6,5 +6,5 @@ create table read_message_log ( primary key (id) ); -alter table read_message_log add constraint fk_read_message_log_chat_room foreign key (chat_room_id) references chatRoom (id); +alter table read_message_log add constraint fk_read_message_log_chat_room foreign key (chat_room_id) references chat_room (id); alter table read_message_log add constraint fk_read_message_reader foreign key (reader_id) references users (id);
Table 13. /auctions/{auctionId}/reviewsTable 14. /auctions/{auctionId}/reviews