diff --git a/src/main/java/gg/agit/konect/domain/chat/service/ChatRoomMembershipService.java b/src/main/java/gg/agit/konect/domain/chat/service/ChatRoomMembershipService.java index 8b94b854e..3dd25d68c 100644 --- a/src/main/java/gg/agit/konect/domain/chat/service/ChatRoomMembershipService.java +++ b/src/main/java/gg/agit/konect/domain/chat/service/ChatRoomMembershipService.java @@ -20,7 +20,6 @@ import gg.agit.konect.domain.club.model.Club; import gg.agit.konect.domain.club.model.ClubMember; import gg.agit.konect.domain.club.repository.ClubMemberRepository; -import gg.agit.konect.domain.user.enums.UserRole; import gg.agit.konect.domain.user.model.User; import gg.agit.konect.domain.user.repository.UserRepository; import gg.agit.konect.global.exception.CustomException; @@ -33,7 +32,7 @@ @Transactional(readOnly = true) public class ChatRoomMembershipService { - private static final int SYSTEM_ADMIN_ID = 1; + public static final int SYSTEM_ADMIN_ID = 1; private final ChatRoomRepository chatRoomRepository; private final ChatRoomMemberRepository chatRoomMemberRepository; @@ -68,7 +67,7 @@ public void updateLastReadAt(Integer roomId, Integer userId, LocalDateTime readA @Transactional(propagation = Propagation.REQUIRES_NEW) public void updateDirectRoomLastReadAt(Integer roomId, User user, LocalDateTime readAt, ChatRoom room) { // 어드민이 SYSTEM_ADMIN 방의 메시지를 읽으면 SYSTEM_ADMIN의 lastReadAt을 업데이트 - if (user.getRole() == UserRole.ADMIN && isSystemAdminRoom(roomId)) { + if (user.isAdmin() && isSystemAdminRoom(roomId)) { chatRoomMemberRepository.updateLastReadAtIfOlder(roomId, SYSTEM_ADMIN_ID, readAt); return; } @@ -134,7 +133,7 @@ private void ensureDirectRoomMemberExists(ChatRoom room, User user, LocalDateTim // 어드민은 SYSTEM_ADMIN 방의 메시지를 조회할 수 있지만, 멤버로 추가되지는 않는다 // (멤버가 추가되면 findByTwoUsers에서 해당 방을 찾지 못해 채팅방이 중복 생성됨) - if (user.getRole() == UserRole.ADMIN && isSystemAdminRoom(room.getId())) { + if (user.isAdmin() && isSystemAdminRoom(room.getId())) { return; } 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 794c114ae..e5d52eb31 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 @@ -1,5 +1,6 @@ package gg.agit.konect.domain.chat.service; +import static gg.agit.konect.domain.chat.service.ChatRoomMembershipService.SYSTEM_ADMIN_ID; import static gg.agit.konect.global.code.ApiResponseCode.*; import java.time.LocalDateTime; @@ -69,7 +70,6 @@ @Transactional(readOnly = true) public class ChatService { - private static final int SYSTEM_ADMIN_ID = 1; private static final String ETC_SECTION_NAME = "기타"; private static final String DEFAULT_GROUP_ROOM_NAME = "그룹 채팅"; @@ -94,7 +94,7 @@ public ChatRoomResponse createOrGetChatRoom(Integer currentUserId, ChatRoomCreat throw CustomException.of(CANNOT_CREATE_CHAT_ROOM_WITH_SELF); } - if (currentUser.getRole() == UserRole.ADMIN && targetUser.getRole() != UserRole.ADMIN) { + if (currentUser.isAdmin() && !targetUser.isAdmin()) { return getOrCreateSystemAdminChatRoomForUser(targetUser, currentUser); } @@ -396,7 +396,7 @@ public ChatMessagePageResponse getMessages(Integer userId, Integer roomId, Integ LocalDateTime readAt = LocalDateTime.now(); if (room.isDirectRoom()) { - boolean isAdminViewingSystemRoom = user.getRole() == UserRole.ADMIN && isSystemAdminRoom(room); + boolean isAdminViewingSystemRoom = user.isAdmin() && isSystemAdminRoom(room); if (isAdminViewingSystemRoom) { chatRoomMembershipService.updateLastReadAt(roomId, SYSTEM_ADMIN_ID, readAt); recordPresenceSafely(roomId, userId); @@ -448,7 +448,7 @@ public ChatMuteResponse toggleMute(Integer userId, Integer roomId) { ensureRoomMember(room, member.getUser(), member.getCreatedAt()); } else if (room.isDirectRoom()) { // 어드민이 SYSTEM_ADMIN 방에 접근하는 경우는 멤버십 체크를 건너뜀 - boolean isAdminAccessingSystemAdminRoom = user.getRole() == UserRole.ADMIN + boolean isAdminAccessingSystemAdminRoom = user.isAdmin() && isSystemAdminRoom(room); if (!isAdminAccessingSystemAdminRoom) { getAccessibleDirectRoomMember(room, user); @@ -491,7 +491,7 @@ public void updateChatRoomName(Integer userId, Integer roomId, ChatRoomNameUpdat private List getDirectChatRooms(Integer userId) { User user = userRepository.getById(userId); - if (user.getRole() == UserRole.ADMIN) { + if (user.isAdmin()) { return getAdminDirectChatRooms(userId); } @@ -620,37 +620,38 @@ private List getGroupChatRooms(Integer userId) { .toList(); } - private ChatMessagePageResponse getDirectChatRoomMessages( - Integer userId, + private ChatMessagePageResponse buildDirectChatRoomMessages( + User user, Integer roomId, Integer page, Integer limit, - LocalDateTime readAt + LocalDateTime readAt, + LocalDateTime visibleMessageFrom, + List sortedReadBaselines, + Integer maskedAdminId ) { - ChatRoom chatRoom = getDirectRoom(roomId); - User user = userRepository.getById(userId); - List members = chatRoomMemberRepository.findByChatRoomId(roomId); - LocalDateTime visibleMessageFrom = prepareDirectRoomAccess(getOrCreateDirectRoomMember(chatRoom, user), - chatRoom); - PageRequest pageable = PageRequest.of(page - 1, limit); Page messages = chatMessageRepository.findByChatRoomId(roomId, visibleMessageFrom, pageable); - List sortedReadBaselines = toSortedReadBaselines(members); - List responseMessages = messages.getContent().stream() .map(message -> { - boolean isRead = message.isSentBy(userId) || !message.getCreatedAt().isAfter(readAt); + Integer senderId = maskedAdminId != null + ? resolveDirectSenderId(message, maskedAdminId) + : message.getSender().getId(); + boolean isMine = maskedAdminId != null + ? shouldDisplayAsOwnMessage(user, message, true) + : message.isSentBy(user.getId()); + boolean isRead = isMine || !message.getCreatedAt().isAfter(readAt); int unreadCount = countUnreadSince(message.getCreatedAt(), sortedReadBaselines); return new ChatMessageDetailResponse( message.getId(), - message.getSender().getId(), + senderId, null, message.getContent(), message.getCreatedAt(), isRead, unreadCount, - message.isSentBy(userId) + isMine ); }) .toList(); @@ -665,6 +666,25 @@ private ChatMessagePageResponse getDirectChatRoomMessages( ); } + private ChatMessagePageResponse getDirectChatRoomMessages( + Integer userId, + Integer roomId, + Integer page, + Integer limit, + LocalDateTime readAt + ) { + ChatRoom chatRoom = getDirectRoom(roomId); + User user = userRepository.getById(userId); + List members = chatRoomMemberRepository.findByChatRoomId(roomId); + LocalDateTime visibleMessageFrom = prepareDirectRoomAccess(getOrCreateDirectRoomMember(chatRoom, user), + chatRoom); + + List sortedReadBaselines = toSortedReadBaselines(members); + + return buildDirectChatRoomMessages(user, roomId, page, limit, readAt, + visibleMessageFrom, sortedReadBaselines, null); + } + private ChatMessagePageResponse getAdminSystemDirectChatRoomMessages( User user, ChatRoom chatRoom, @@ -676,39 +696,11 @@ private ChatMessagePageResponse getAdminSystemDirectChatRoomMessages( List members = chatRoomMemberRepository.findByChatRoomId(roomId); LocalDateTime visibleMessageFrom = resolveAdminSystemRoomVisibleMessageFrom(members); - PageRequest pageable = PageRequest.of(page - 1, limit); - Page messages = chatMessageRepository.findByChatRoomId(roomId, visibleMessageFrom, pageable); - List sortedReadBaselines = toAdminChatReadBaselines(members); - Integer maskedAdminId = getMaskedAdminId(user, chatRoom); - List responseMessages = messages.getContent().stream() - .map(message -> { - Integer senderId = resolveDirectSenderId(message, maskedAdminId); - boolean isMine = shouldDisplayAsOwnMessage(user, message, true); - boolean isRead = isMine || !message.getCreatedAt().isAfter(readAt); - int unreadCount = countUnreadSince(message.getCreatedAt(), sortedReadBaselines); - return new ChatMessageDetailResponse( - message.getId(), - senderId, - null, - message.getContent(), - message.getCreatedAt(), - isRead, - unreadCount, - isMine - ); - }) - .toList(); - return new ChatMessagePageResponse( - messages.getTotalElements(), - messages.getNumberOfElements(), - messages.getTotalPages(), - messages.getNumber() + 1, - null, - responseMessages - ); + return buildDirectChatRoomMessages(user, roomId, page, limit, readAt, + visibleMessageFrom, sortedReadBaselines, maskedAdminId); } private ChatMessageDetailResponse sendDirectMessage( @@ -720,7 +712,7 @@ private ChatMessageDetailResponse sendDirectMessage( User sender = userRepository.getById(userId); // 어드민이 SYSTEM_ADMIN 방에 메시지를 보내는 경우 - boolean isAdminSendingToSystemAdminRoom = sender.getRole() == UserRole.ADMIN + boolean isAdminSendingToSystemAdminRoom = sender.isAdmin() && isSystemAdminRoom(chatRoom); ChatRoomMember senderMember = null; @@ -1175,7 +1167,7 @@ private Map getUnreadCountMap(List chatRoomIds, Integ } private Integer getMaskedAdminId(User user, ChatRoom chatRoom) { - if (user.getRole() == UserRole.ADMIN) { + if (user.isAdmin()) { return null; } @@ -1197,7 +1189,7 @@ private Integer getMaskedAdminId(User user, ChatRoom chatRoom) { } private void publishAdminChatEventIfNeeded(boolean isSystemAdminRoom, User sender, String content) { - if (isSystemAdminRoom && sender.getRole() != UserRole.ADMIN) { + if (isSystemAdminRoom && !sender.isAdmin()) { eventPublisher.publishEvent(AdminChatReceivedEvent.of(sender.getId(), sender.getName(), content)); } } @@ -1260,7 +1252,7 @@ private void ensureDirectRoomRequester(ChatRoom room, User user, LocalDateTime j private boolean shouldSkipSystemAdminMembership(ChatRoom room, User user) { // 문의방은 SYSTEM_ADMIN + 일반 사용자 2인 구조를 전제로 재사용(findByTwoUsers)되므로, // 생성/재오픈 경로에서도 일반 ADMIN을 멤버로 추가하면 안 된다. - return user.getRole() == UserRole.ADMIN && isSystemAdminRoom(room); + return user.isAdmin() && isSystemAdminRoom(room); } private String normalizeCustomRoomName(String roomName) { @@ -1296,11 +1288,10 @@ private void updateClubMessageLastReadAt(Integer roomId, Integer userId, LocalDa } private List toSortedReadBaselines(List members) { - List baselines = members.stream() + return members.stream() .map(ChatRoomMember::getLastReadAt) .sorted() .toList(); - return baselines; } private List toAdminChatReadBaselines(List members) { @@ -1308,7 +1299,7 @@ private List toAdminChatReadBaselines(List member LocalDateTime userLastReadAt = null; for (ChatRoomMember member : members) { - if (member.getUser().getRole() == UserRole.ADMIN) { + if (member.getUser().isAdmin()) { if (adminLastReadAt == null || member.getLastReadAt().isAfter(adminLastReadAt)) { adminLastReadAt = member.getLastReadAt(); } @@ -1383,7 +1374,7 @@ private ChatRoomMember getOrCreateDirectRoomMember(ChatRoom chatRoom, User user) return chatRoomMemberRepository.findByChatRoomIdAndUserId(chatRoom.getId(), user.getId()) .orElseGet(() -> { // 어드민은 SYSTEM_ADMIN 방에 멤버로 추가되지 않음 - if (user.getRole() == UserRole.ADMIN && isSystemAdminRoom(chatRoom)) { + if (user.isAdmin() && isSystemAdminRoom(chatRoom)) { throw CustomException.of(FORBIDDEN_CHAT_ROOM_ACCESS); } throw CustomException.of(FORBIDDEN_CHAT_ROOM_ACCESS); @@ -1440,13 +1431,13 @@ private boolean shouldDisplayAsOwnMessage( boolean isAdminViewingSystemRoom ) { if (isAdminViewingSystemRoom) { - return message.getSender().getRole() == UserRole.ADMIN; + return message.getSender().isAdmin(); } return message.isSentBy(currentUser.getId()); } private Integer resolveDirectSenderId(ChatMessage message, Integer maskedAdminId) { - if (maskedAdminId != null && message.getSender().getRole() == UserRole.ADMIN) { + if (maskedAdminId != null && message.getSender().isAdmin()) { return maskedAdminId; } return message.getSender().getId(); @@ -1531,26 +1522,29 @@ private User resolveDirectChatPartner(List members, Integer user } private User findNonAdminUser(List members) { - return members.stream() - .map(ChatRoomMember::getUser) - .filter(memberUser -> memberUser.getRole() != UserRole.ADMIN) - .findFirst() - .orElse(null); + Map userMap = members.stream() + .collect(Collectors.toMap( + ChatRoomMember::getUserId, + ChatRoomMember::getUser, + (existing, replacement) -> existing + )); + List memberInfos = members.stream() + .map(m -> new MemberInfo(m.getUserId(), m.getCreatedAt())) + .toList(); + return findNonAdminUserFromMemberInfo(memberInfos, userMap); } private User resolveDirectMessageReceiver(List members, User sender) { - if (sender.getRole() == UserRole.ADMIN) { - User nonAdminUser = findNonAdminUser(members); - if (nonAdminUser != null) { - return nonAdminUser; - } - } - - User partner = resolveDirectChatPartner(members, sender.getId()); - if (partner == null) { - throw CustomException.of(FORBIDDEN_CHAT_ROOM_ACCESS); - } - return partner; + Map userMap = members.stream() + .collect(Collectors.toMap( + ChatRoomMember::getUserId, + ChatRoomMember::getUser, + (existing, replacement) -> existing + )); + List memberInfos = members.stream() + .map(m -> new MemberInfo(m.getUserId(), m.getCreatedAt())) + .toList(); + return resolveMessageReceiverFromMemberInfo(sender, memberInfos, userMap); } private User findDirectPartnerFromMemberInfo( @@ -1585,7 +1579,7 @@ private User findNonAdminUserFromMemberInfo(List memberInfos, Map userMap.get(info.userId())) .filter(Objects::nonNull) - .filter(user -> user.getRole() != UserRole.ADMIN) + .filter(user -> !user.isAdmin()) .findFirst() .orElse(null); } @@ -1595,7 +1589,7 @@ private User resolveMessageReceiverFromMemberInfo( List memberInfos, Map userMap ) { - if (sender.getRole() == UserRole.ADMIN) { + if (sender.isAdmin()) { User nonAdminUser = findNonAdminUserFromMemberInfo(memberInfos, userMap); if (nonAdminUser != null) { return nonAdminUser;