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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.codeit.side.chat.adapter.in.web.response;

import com.codeit.side.chat.domain.ChatMessage;
import com.codeit.side.chat.domain.UserChatMessage;
import com.codeit.side.user.domain.User;

import java.time.LocalDateTime;

Expand All @@ -10,16 +11,19 @@ public record ChatMessageResponse(
Long userId,
String userNickname,
String content,
LocalDateTime createdAt
LocalDateTime createdAt,
String userImage
) {
public static ChatMessageResponse from(ChatMessage chatMessage) {
public static ChatMessageResponse from(UserChatMessage chatMessage) {
User user = chatMessage.getUser();
return new ChatMessageResponse(
chatMessage.getId(),
chatMessage.getRoomId(),
chatMessage.getUserId(),
chatMessage.getUserNickname(),
chatMessage.getContent(),
chatMessage.getCreatedAt()
chatMessage.getChatMessage().getId(),
chatMessage.getChatMessage().getRoomId(),
chatMessage.getChatMessage().getUserId(),
chatMessage.getChatMessage().getUserNickname(),
chatMessage.getChatMessage().getContent(),
chatMessage.getChatMessage().getCreatedAt(),
user.isHasImage() ? "https://codeit-doit.s3.ap-northeast-2.amazonaws.com/user/%s/image.jpg".formatted(user.getId()) : ""
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,21 @@ public void sendMessage(
ChatType.CHAT,
chatMessageReceived.getContent()
);
String destination = "/topic/room/%s".formatted(id);

messagingTemplate.convertAndSend(destination, ChatMessageSend.of(chatMessage, ""));
String destination = "/topic/room/" + id;

String userImage = user.isHasImage() ? "https://codeit-doit.s3.ap-northeast-2.amazonaws.com/user/%s/image.jpg".formatted(user.getId()) : "";
chatMessageUseCase.save(chatMessage);
messagingTemplate.convertAndSend(destination, ChatMessageSend.of(chatMessage, userImage));
}

@MessageMapping("/room/{id}/read")
public void readMessage(
@Header(name = "simpSessionAttributes") Map<String, Object> sessionAttributes,
@DestinationVariable Long id
) {
User user = (User) sessionAttributes.get("user");
chatMessageUseCase.findChatRoomBy(id, user.getId());
chatMessageUseCase.read(id, user.getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,14 @@ public boolean existsByChatRoomIdAndUserId(Long id, Long userId) {
public void join(Long id, Long userId) {
chatMemberJpaRepository.save(ChatMemberEntity.of(id, userId));
}

@Override
public List<ChatMemberEntity> findAllMemberById(Long roomId) {
return chatMemberJpaRepository.findAllByChatRoomId(roomId);
}

@Override
public void leave(Long chatRoomId, Long userId) {
chatMemberJpaRepository.deleteByChatRoomIdAndUserId(chatRoomId, userId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.codeit.side.chat.adapter.out.persistence;

import com.codeit.side.chat.adapter.out.persistence.entity.ChatMessageReadEntity;
import com.codeit.side.chat.adapter.out.persistence.jpa.ChatMessageReadJpaRepository;
import com.codeit.side.chat.application.port.out.ChatMessageReadRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class ChatMessageReadRepositoryImpl implements ChatMessageReadRepository {
private final ChatMessageReadJpaRepository chatMessageReadJpaRepository;

@Override
public void save(Long roomId, List<Long> userIds) {
List<ChatMessageReadEntity> chatMessageReadEntities = userIds.stream()
.map(userId -> ChatMessageReadEntity.of(roomId, userId))
.toList();
chatMessageReadJpaRepository.saveAll(chatMessageReadEntities);
}

@Override
public void read(Long roomId, Long userId) {
chatMessageReadJpaRepository.findAllByChatRoomIdAndUserIdAndIsReadFalse(roomId, userId)
.forEach(ChatMessageReadEntity::read);
}

@Override
public List<ChatMessageReadEntity> findAllUnreadMessages(Long userId, List<Long> chatRoomIds) {
return chatMessageReadJpaRepository.findAllByUserIdAndChatRoomIdInAndIsReadFalse(userId, chatRoomIds);
}

@Override
public int findUnreadMessagesBy(Long chatRoomId, Long userId) {
return chatMessageReadJpaRepository.findAllByChatRoomIdAndUserIdAndIsReadFalse(chatRoomId, userId)
.size();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ public class ChatRepositoryImpl implements ChatMessageRepository {

@Override
@Transactional
public void save(ChatMessage chatMessage) {
chatMessageJpaRepository.save(ChatMessageEntity.from(chatMessage));
public ChatMessage save(ChatMessage chatMessage) {
return chatMessageJpaRepository.save(ChatMessageEntity.from(chatMessage))
.toDomain();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.codeit.side.chat.adapter.out.persistence.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(
name = "chat_message_read",
indexes = @Index(name = "idx_chat_room", columnList = "chatRoomId")
)
public class ChatMessageReadEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Long chatRoomId;

private Long userId;

private Boolean isRead;

public static ChatMessageReadEntity of(Long chatRoomId, Long userId) {
return new ChatMessageReadEntity(null, chatRoomId, userId, false);
}

public void read() {
isRead = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ public interface ChatMemberJpaRepository extends JpaRepository<ChatMemberEntity,
List<ChatMemberEntity> findAllByChatRoomId(Long chatRoomId);

Optional<ChatMemberEntity> findByChatRoomIdAndUserId(Long chatRoomId, Long userId);

void deleteByChatRoomIdAndUserId(Long chatRoomId, Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.codeit.side.chat.adapter.out.persistence.jpa;

import com.codeit.side.chat.adapter.out.persistence.entity.ChatMessageReadEntity;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Collection;
import java.util.List;

public interface ChatMessageReadJpaRepository extends JpaRepository<ChatMessageReadEntity, Long> {
List<ChatMessageReadEntity> findAllByChatRoomIdAndUserIdAndIsReadFalse(Long roomId, Long userId);

List<ChatMessageReadEntity> findAllByUserIdAndChatRoomIdInAndIsReadFalse(Long userId, Collection<Long> chatRoomIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
import com.codeit.side.chat.domain.ChatRoomInfo;

import java.util.List;
import java.util.Map;

public interface ChatMessageUseCase {
void save(ChatMessage chatMessage);

void createChatRoom(String email, Long lighteningId, String chatRoomName);
ChatRoom createChatRoom(String email, Long lighteningId, String chatRoomName);

List<ChatRoomInfo> findAllChatRooms(String email);

Expand All @@ -23,4 +24,14 @@ public interface ChatMessageUseCase {
ChatRoom getChatRoomByLighteningId(Long lighteningId);

List<ChatRoom> findAllChatRoomsByLighteningIds(List<Long> lighteningIds);

void read(Long roomId, Long userId);

void leaveChatRoom(Long id, String email);

void joinChatRoomByLighteningId(Long id, String email);

Map<Long, Integer> countAllUnreadMessages(String email, List<Long> chatRoomIds);

int countUnreadMessages(Long lighteningId, String email);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.codeit.side.chat.application.port.out;

import com.codeit.side.chat.adapter.out.persistence.entity.ChatMemberEntity;
import com.codeit.side.chat.domain.command.ChatRoomCommand;

import java.util.List;
Expand All @@ -13,4 +14,8 @@ public interface ChatMemberRepository {
boolean existsByChatRoomIdAndUserId(Long id, Long userId);

void join(Long id, Long userId);

List<ChatMemberEntity> findAllMemberById(Long roomId);

void leave(Long chatRoomId, Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.codeit.side.chat.application.port.out;

import com.codeit.side.chat.adapter.out.persistence.entity.ChatMessageReadEntity;

import java.util.List;

public interface ChatMessageReadRepository {
void save(Long roomId, List<Long> userIds);

void read(Long roomId, Long userId);

List<ChatMessageReadEntity> findAllUnreadMessages(Long id, List<Long> chatRoomIds);

int findUnreadMessagesBy(Long lighteningId, Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.util.Map;

public interface ChatMessageRepository {
void save(ChatMessage chatMessage);
ChatMessage save(ChatMessage chatMessage);

Map<Long, ChatMessage> findAllLastMessageByIds(List<Long> chatRoomIds);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.codeit.side.chat.application.service;

import com.codeit.side.chat.adapter.out.persistence.entity.ChatMemberEntity;
import com.codeit.side.chat.adapter.out.persistence.entity.ChatMessageReadEntity;
import com.codeit.side.chat.application.port.in.ChatMessageUseCase;
import com.codeit.side.chat.application.port.out.ChatMemberRepository;
import com.codeit.side.chat.application.port.out.ChatMessageReadRepository;
import com.codeit.side.chat.application.port.out.ChatMessageRepository;
import com.codeit.side.chat.application.port.out.ChatRoomRepository;
import com.codeit.side.chat.domain.ChatMessage;
import com.codeit.side.chat.domain.ChatMessages;
import com.codeit.side.chat.domain.ChatRoom;
import com.codeit.side.chat.domain.ChatRoomInfo;
import com.codeit.side.chat.domain.*;
import com.codeit.side.chat.domain.command.ChatRoomCommand;
import com.codeit.side.common.adapter.exception.IllegalRequestException;
import com.codeit.side.user.application.port.out.UserQueryRepository;
Expand All @@ -19,6 +19,8 @@

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Primary
@Service
Expand All @@ -29,21 +31,28 @@ public class ChatMessageService implements ChatMessageUseCase {
private final UserQueryRepository userQueryRepository;
private final ChatRoomRepository chatRoomRepository;
private final ChatMemberRepository chatMemberRepository;
private final ChatMessageReadRepository chatMessageReadRepository;

@Override
@Transactional
public void save(ChatMessage chatMessage) {
chatMessageRepository.save(chatMessage);
ChatMessage savedChatMessage = chatMessageRepository.save(chatMessage);
List<ChatMemberEntity> chatMemberEntities = chatMemberRepository.findAllMemberById(savedChatMessage.getRoomId());
List<Long> userIds = chatMemberEntities.stream()
.map(ChatMemberEntity::getUserId)
.toList();
chatMessageReadRepository.save(savedChatMessage.getRoomId(), userIds);
}

@Override
@Transactional
public void createChatRoom(String email, Long lighteningId, String chatRoomName) {
public ChatRoom createChatRoom(String email, Long lighteningId, String chatRoomName) {
User host = userQueryRepository.getByEmail(email)
.toDomain();
ChatRoomCommand userChatRoomCommand = ChatRoomCommand.of(chatRoomName, lighteningId, host.getId());
ChatRoom chatRoom = chatRoomRepository.save(userChatRoomCommand);
chatMemberRepository.save(chatRoom.getId(), userChatRoomCommand);
return chatRoom;
}

@Override
Expand Down Expand Up @@ -77,7 +86,21 @@ public ChatMessages findAllMessagesByRoomId(Long roomId, String email, Long offs
List<ChatMessage> messages = chatMessages.stream()
.limit(size)
.toList();
return ChatMessages.of(messages, isLast);
List<Long> userIds = extractUserIds(chatMessages);
Map<Long, User> idToUser = userQueryRepository.findAllByIds(userIds)
.stream()
.collect(Collectors.toMap(User::getId, Function.identity()));
List<UserChatMessage> userChatMessages = messages.stream()
.map(message -> UserChatMessage.of(message, idToUser.get(message.getUserId())))
.toList();
return ChatMessages.of(userChatMessages, isLast);
}

private List<Long> extractUserIds(List<ChatMessage> chatMessages) {
return chatMessages.stream()
.map(ChatMessage::getUserId)
.distinct()
.toList();
}

@Override
Expand All @@ -86,10 +109,38 @@ public void joinChatRoom(Long id, String email) {
User user = userQueryRepository.getByEmail(email)
.toDomain();
ChatRoom chatRoom = chatRoomRepository.getBy(id);
if (chatMemberRepository.existsByChatRoomIdAndUserId(chatRoom.getId(), user.getId())) {
throw new IllegalRequestException("이미 채팅방에 참여하고 있는 사용자입니다.");
chatMemberRepository.join(chatRoom.getId(), user.getId());
}

@Override
@Transactional
public void joinChatRoomByLighteningId(Long id, String email) {
User user = userQueryRepository.getByEmail(email)
.toDomain();
ChatRoom chatRoom = chatRoomRepository.getByLighteningId(id);
chatMemberRepository.join(chatRoom.getId(), user.getId());
}

@Override
public Map<Long, Integer> countAllUnreadMessages(String email, List<Long> chatRoomIds) {
if ("".equals(email)) {
return Map.of();
}
User user = userQueryRepository.getByEmail(email)
.toDomain();
List<ChatMessageReadEntity> chatMessageReadEntities = chatMessageReadRepository.findAllUnreadMessages(user.getId(), chatRoomIds);
return chatMessageReadEntities.stream()
.collect(Collectors.groupingBy(ChatMessageReadEntity::getChatRoomId, Collectors.collectingAndThen(Collectors.counting(), Long::intValue)));
}

@Override
public int countUnreadMessages(Long chatRoomId, String email) {
if ("".equals(email)) {
return 0;
}
chatMemberRepository.join(id, user.getId());
User user = userQueryRepository.getByEmail(email)
.toDomain();
return chatMessageReadRepository.findUnreadMessagesBy(chatRoomId, user.getId());
}

@Override
Expand All @@ -102,6 +153,21 @@ public List<ChatRoom> findAllChatRoomsByLighteningIds(List<Long> lighteningIds)
return chatRoomRepository.findAllByLighteningIds(lighteningIds);
}

@Override
@Transactional
public void read(Long roomId, Long userId) {
chatMessageReadRepository.read(roomId, userId);
}

@Override
@Transactional
public void leaveChatRoom(Long id, String email) {
User user = userQueryRepository.getByEmail(email)
.toDomain();
ChatRoom chatRoom = chatRoomRepository.getByLighteningId(id);
chatMemberRepository.leave(chatRoom.getId(), user.getId());
}

private List<ChatRoomInfo> createChatRoomInfos(List<ChatRoom> chatRooms, Map<Long, ChatMessage> allLastMessageByIds, Map<Long, Integer> idToMemberSize) {
return chatRooms.stream()
.map(chatRoom -> createChatRoomInfo(chatRoom, allLastMessageByIds.get(chatRoom.getId()), idToMemberSize.get(chatRoom.getId())))
Expand Down
Loading
Loading