diff --git a/src/main/java/gg/agit/konect/domain/chat/repository/ChatRoomMemberRepository.java b/src/main/java/gg/agit/konect/domain/chat/repository/ChatRoomMemberRepository.java index e2459dd2a..29cc87644 100644 --- a/src/main/java/gg/agit/konect/domain/chat/repository/ChatRoomMemberRepository.java +++ b/src/main/java/gg/agit/konect/domain/chat/repository/ChatRoomMemberRepository.java @@ -55,7 +55,7 @@ boolean existsByChatRoomIdAndUserId( List findByChatRoomIds(@Param("chatRoomIds") List chatRoomIds); @Query(""" - SELECT crm.id.chatRoomId, crm.id.userId + SELECT crm.id.chatRoomId, crm.id.userId, crm.createdAt FROM ChatRoomMember crm WHERE crm.id.chatRoomId IN :chatRoomIds """) diff --git a/src/main/java/gg/agit/konect/domain/chat/service/ChatService.java b/src/main/java/gg/agit/konect/domain/chat/service/ChatService.java index a1af2b3ba..43d76d479 100644 --- a/src/main/java/gg/agit/konect/domain/chat/service/ChatService.java +++ b/src/main/java/gg/agit/konect/domain/chat/service/ChatService.java @@ -206,12 +206,23 @@ private List getDirectChatRooms(Integer userId) { List roomSummaries = new ArrayList<>(); List personalChatRooms = chatRoomRepository.findByUserId(userId); - Map> roomMembersMap = getRoomMembersMap(personalChatRooms); + Map> roomMemberInfoMap = getRoomMemberInfoMap(personalChatRooms); Map personalUnreadCountMap = getUnreadCountMap(extractChatRoomIds(personalChatRooms), userId); + List allUserIds = roomMemberInfoMap.values().stream() + .flatMap(List::stream) + .map(MemberInfo::userId) + .distinct() + .toList(); + + Map userMap = allUserIds.isEmpty() + ? Map.of() + : userRepository.findAllByIdIn(allUserIds).stream() + .collect(Collectors.toMap(User::getId, u -> u)); + for (ChatRoom chatRoom : personalChatRooms) { - List members = roomMembersMap.getOrDefault(chatRoom.getId(), List.of()); - User chatPartner = findDirectPartner(members, user.getId()); + List memberInfos = roomMemberInfoMap.getOrDefault(chatRoom.getId(), List.of()); + User chatPartner = findDirectPartnerFromMemberInfo(memberInfos, user.getId(), userMap); if (chatPartner == null) { continue; } @@ -242,11 +253,12 @@ private List getAdminDirectChatRooms() { List roomSummaries = new ArrayList<>(); List adminUserRooms = chatRoomRepository.findAllAdminUserDirectRooms(UserRole.ADMIN); - Map> roomUserIdsMap = getRoomUserIdsMap(adminUserRooms); + Map> roomMemberInfoMap = getRoomMemberInfoMap(adminUserRooms); Map adminUnreadCountMap = getAdminUnreadCountMap(extractChatRoomIds(adminUserRooms)); - List allUserIds = roomUserIdsMap.values().stream() + List allUserIds = roomMemberInfoMap.values().stream() .flatMap(List::stream) + .map(MemberInfo::userId) .distinct() .toList(); @@ -256,8 +268,8 @@ private List getAdminDirectChatRooms() { .collect(Collectors.toMap(User::getId, user -> user)); for (ChatRoom chatRoom : adminUserRooms) { - List memberUserIds = roomUserIdsMap.getOrDefault(chatRoom.getId(), List.of()); - User nonAdminUser = findNonAdminUserFromIds(memberUserIds, userMap); + List memberInfos = roomMemberInfoMap.getOrDefault(chatRoom.getId(), List.of()); + User nonAdminUser = findNonAdminUserFromMemberInfo(memberInfos, userMap); if (nonAdminUser == null) { continue; } @@ -342,8 +354,16 @@ private ChatMessageDetailResponse sendDirectMessage( User sender = userRepository.getById(userId); getOrCreateDirectRoomMember(chatRoom, sender); - List members = chatRoomMemberRepository.findByChatRoomId(roomId); - User receiver = resolveMessageReceiver(sender, members); + List memberResults = chatRoomMemberRepository.findRoomMemberIdsByChatRoomIds(List.of(roomId)); + List memberInfos = memberResults.stream() + .map(row -> new MemberInfo((Integer)row[1], (LocalDateTime)row[2])) + .toList(); + + List memberUserIds = memberInfos.stream().map(MemberInfo::userId).toList(); + Map userMap = userRepository.findAllByIdIn(memberUserIds).stream() + .collect(Collectors.toMap(User::getId, u -> u)); + + User receiver = resolveMessageReceiverFromMemberInfo(sender, memberInfos, userMap); ChatMessage chatMessage = chatMessageRepository.save( ChatMessage.of(chatRoom, sender, request.content()) @@ -580,8 +600,22 @@ private Integer getMaskedAdminId(User user, ChatRoom chatRoom) { return null; } - List members = chatRoomMemberRepository.findByChatRoomId(chatRoom.getId()); - User adminUser = findAdminMember(members); + List memberResults = chatRoomMemberRepository.findRoomMemberIdsByChatRoomIds( + List.of(chatRoom.getId()) + ); + List memberInfos = memberResults.stream() + .map(row -> new MemberInfo((Integer)row[1], (LocalDateTime)row[2])) + .toList(); + + List memberUserIds = memberInfos.stream().map(MemberInfo::userId).toList(); + if (memberUserIds.isEmpty()) { + return null; + } + + Map userMap = userRepository.findAllByIdIn(memberUserIds).stream() + .collect(Collectors.toMap(User::getId, u -> u)); + + User adminUser = findAdminUserFromMemberInfo(memberInfos, userMap); if (adminUser == null) { return null; } @@ -700,11 +734,20 @@ private ChatRoomMember getOrCreateDirectRoomMember(ChatRoom chatRoom, User user) } private boolean isAdminUserRoom(ChatRoom chatRoom) { - List members = chatRoomMemberRepository.findByChatRoomId(chatRoom.getId()); - boolean hasAdmin = members.stream() - .anyMatch(m -> m.getUser().getRole() == UserRole.ADMIN); - boolean hasNonAdmin = members.stream() - .anyMatch(m -> m.getUser().getRole() != UserRole.ADMIN); + List memberIds = chatRoomMemberRepository.findRoomMemberIdsByChatRoomIds( + List.of(chatRoom.getId()) + ); + List userIds = memberIds.stream() + .map(row -> (Integer)row[1]) + .toList(); + + if (userIds.isEmpty()) { + return false; + } + + List users = userRepository.findAllByIdIn(userIds); + boolean hasAdmin = users.stream().anyMatch(u -> u.getRole() == UserRole.ADMIN); + boolean hasNonAdmin = users.stream().anyMatch(u -> u.getRole() != UserRole.ADMIN); return hasAdmin && hasNonAdmin; } @@ -725,7 +768,10 @@ private Map> getRoomMembersMap(List room .collect(Collectors.groupingBy(ChatRoomMember::getChatRoomId)); } - private Map> getRoomUserIdsMap(List rooms) { + private record MemberInfo(Integer userId, LocalDateTime createdAt) { + } + + private Map> getRoomMemberInfoMap(List rooms) { if (rooms.isEmpty()) { return Map.of(); } @@ -733,13 +779,15 @@ private Map> getRoomUserIdsMap(List rooms) { List roomIds = rooms.stream().map(ChatRoom::getId).toList(); List results = chatRoomMemberRepository.findRoomMemberIdsByChatRoomIds(roomIds); - Map> roomUserIdsMap = new HashMap<>(); + Map> roomMemberInfoMap = new HashMap<>(); for (Object[] row : results) { Integer chatRoomId = (Integer)row[0]; - Integer userId = (Integer)row[1]; - roomUserIdsMap.computeIfAbsent(chatRoomId, k -> new ArrayList<>()).add(userId); + Integer memberId = (Integer)row[1]; + LocalDateTime createdAt = (LocalDateTime)row[2]; + roomMemberInfoMap.computeIfAbsent(chatRoomId, k -> new ArrayList<>()) + .add(new MemberInfo(memberId, createdAt)); } - return roomUserIdsMap; + return roomMemberInfoMap; } private User findDirectPartner(List members, Integer userId) { @@ -750,6 +798,18 @@ private User findDirectPartner(List members, Integer userId) { .orElse(null); } + private User findDirectPartnerFromMemberInfo( + List memberInfos, + Integer userId, + Map userMap + ) { + return memberInfos.stream() + .filter(info -> !info.userId().equals(userId)) + .min(Comparator.comparing(MemberInfo::createdAt)) + .map(info -> userMap.get(info.userId())) + .orElse(null); + } + private User findNonAdminMember(List members) { return members.stream() .map(ChatRoomMember::getUser) @@ -758,15 +818,26 @@ private User findNonAdminMember(List members) { .orElse(null); } - private User findNonAdminUserFromIds(List userIds, Map userMap) { - return userIds.stream() - .map(userMap::get) + private User findNonAdminUserFromMemberInfo(List memberInfos, Map userMap) { + return memberInfos.stream() + .sorted(Comparator.comparing(MemberInfo::createdAt)) + .map(info -> userMap.get(info.userId())) .filter(Objects::nonNull) .filter(user -> user.getRole() != UserRole.ADMIN) .findFirst() .orElse(null); } + private User findAdminUserFromMemberInfo(List memberInfos, Map userMap) { + return memberInfos.stream() + .sorted(Comparator.comparing(MemberInfo::createdAt)) + .map(info -> userMap.get(info.userId())) + .filter(Objects::nonNull) + .filter(user -> user.getRole() == UserRole.ADMIN) + .findFirst() + .orElse(null); + } + private User findAdminMember(List members) { return members.stream() .map(ChatRoomMember::getUser) @@ -790,4 +861,23 @@ private User resolveMessageReceiver(User sender, List members) { return partner; } + private User resolveMessageReceiverFromMemberInfo( + User sender, + List memberInfos, + Map userMap + ) { + if (sender.getRole() == UserRole.ADMIN) { + User nonAdminUser = findNonAdminUserFromMemberInfo(memberInfos, userMap); + if (nonAdminUser != null) { + return nonAdminUser; + } + } + + User partner = findDirectPartnerFromMemberInfo(memberInfos, sender.getId(), userMap); + if (partner == null) { + throw CustomException.of(FORBIDDEN_CHAT_ROOM_ACCESS); + } + return partner; + } + }