From 47cc7c9c5caea16a9fb5e48c2ab23495bb43827a Mon Sep 17 00:00:00 2001 From: sooyeon_nine <124496650+KooSuYeon@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:18:40 +0900 Subject: [PATCH] =?UTF-8?q?QA=EB=A5=BC=20=EC=9C=84=ED=95=9C=20dev=20->=20p?= =?UTF-8?q?rod=20(#257)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * hotfix/file-profileImg-1: File presignURL ID로 가져오기 작업 - ProfileImg (#253) * Feat/single chatroom exit : 싱글 채팅방 퇴장 및 혼자 남아있을 경우 (상대방 퇴장 시)알림 구현 (#255) * feat/singleChatroom-1: 싱글 채팅방 퇴장 구현 - 기존 채팅방 퇴장은 그룹 채팅방 퇴장만 구현되어 있음 -> 싱글 채팅방 퇴장도 추가 구현 - 그룹 채팅방은 Redisson 처리한 사항이 있어 DB 저장 작업이 필수적임 -> 구별되게 그룹 채팅방 퇴장과 싱글 채팅방 퇴장을 구분 - 채팅 퇴장 시 퇴장 채팅 저장과 Redis 발행은 기존대로 유지 (채팅 보내기와 동일하게 동작함) * feat/singleChatroom-2: 채팅방 퇴장 시 혼자 남은 채팅방 알림구현 - 그룹, 싱글 알림 모두 구현 - 기존 알림 서비스와 동일 - Set의 members에서 한 명의 유저만 남아있을 경우 stream.findFirst() 사용함 - 사용자 언어설정에 따른 번역 알림 추가 * feat/singleChatroom-isRead-1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현 (#256) * feat/singleChatroom-isRead- 1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현 - Chat 엔티티에 해당 Boolean 값인 isOtherRead 생성 - 읽음 대상자 (상대방)이 GET :chats?chatroomId={채팅방 ID}를 하면 해당 isOtherRead를 true로 바꿔줌 * hotfix/chatroom-bookmark-individual-1: 채팅방 별 북마크 조회 가능하도록 수정 * feat/singleChatroom-isRead- 2: 싱글 채팅방 퇴장 시 알림 구현 사항 되돌리기 - 이유 : 불필요 --- .../api/controller/BookmarkController.java | 4 +- .../dife/api/handler/DisconnectHandler.java | 3 +- .../dife/api/handler/NotificationHandler.java | 62 ++++++++++++++----- src/main/java/com/dife/api/model/Chat.java | 2 + .../dife/api/model/dto/ChatResponseDto.java | 2 + .../api/repository/BookmarkRepository.java | 10 ++- .../com/dife/api/service/BookmarkService.java | 17 ++--- .../com/dife/api/service/ChatService.java | 39 ++++++++---- .../com/dife/api/service/ChatroomService.java | 3 +- .../com/dife/api/service/MemberService.java | 7 --- .../resources/db/changelog/v1.0/v1.0.4.xml | 12 ++++ .../whenSingleChatroomAlone.properties | 5 ++ 12 files changed, 115 insertions(+), 51 deletions(-) create mode 100644 src/main/resources/db/changelog/v1.0/v1.0.4.xml create mode 100644 src/main/resources/notification/whenSingleChatroomAlone.properties diff --git a/src/main/java/com/dife/api/controller/BookmarkController.java b/src/main/java/com/dife/api/controller/BookmarkController.java index 56b5d7f2..f54d6e63 100644 --- a/src/main/java/com/dife/api/controller/BookmarkController.java +++ b/src/main/java/com/dife/api/controller/BookmarkController.java @@ -35,9 +35,9 @@ public ResponseEntity createBookmark( return ResponseEntity.status(CREATED).body(responseDto); } - @GetMapping("/{chatroomId}") + @GetMapping("/") public ResponseEntity> getBookmarkChats( - @PathVariable(name = "chatroomId") Long chatroomId, Authentication authentication) { + @RequestParam(name = "chatroomId") Long chatroomId, Authentication authentication) { List bookmarks = bookmarkService.getChatroomBookmarks(chatroomId, authentication.getName()); return ResponseEntity.ok(bookmarks); diff --git a/src/main/java/com/dife/api/handler/DisconnectHandler.java b/src/main/java/com/dife/api/handler/DisconnectHandler.java index 87f0bf38..34ee7fdc 100644 --- a/src/main/java/com/dife/api/handler/DisconnectHandler.java +++ b/src/main/java/com/dife/api/handler/DisconnectHandler.java @@ -65,8 +65,7 @@ public boolean isFull(Chatroom chatroom) { } public boolean isEmpty(Chatroom chatroom) { - ChatroomSetting setting = chatroom.getChatroomSetting(); - return setting.getCount() < 1; + return chatroom.getMembers().isEmpty(); } public void disconnect(Long chatroomId, String sessionId) { diff --git a/src/main/java/com/dife/api/handler/NotificationHandler.java b/src/main/java/com/dife/api/handler/NotificationHandler.java index 20952e6a..d61d903f 100644 --- a/src/main/java/com/dife/api/handler/NotificationHandler.java +++ b/src/main/java/com/dife/api/handler/NotificationHandler.java @@ -1,31 +1,59 @@ package com.dife.api.handler; -import com.dife.api.model.Chatroom; -import com.dife.api.model.ChatroomSetting; +import com.dife.api.model.*; +import com.dife.api.service.NotificationService; +import java.time.LocalDateTime; +import java.util.*; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.simp.SimpMessageSendingOperations; -import org.springframework.messaging.simp.stomp.StompCommand; -import org.springframework.messaging.simp.stomp.StompHeaderAccessor; @Configuration @RequiredArgsConstructor public class NotificationHandler { - private final SimpMessageSendingOperations messagingTemplate; + private final NotificationService notificationService; - public void isAlone(Chatroom chatroom, String sessionId) { - ChatroomSetting setting = chatroom.getChatroomSetting(); - if (setting.getCount() < 2) { - notificate(chatroom.getId(), sessionId); - } + public void isAlone(Chatroom chatroom, Member exitMember) { + if (chatroom.getMembers().size() < 2 && chatroom.getChatroomType() == ChatroomType.GROUP) + notificate(chatroom, exitMember); } - public void notificate(Long chatroomId, String sessionId) { - StompHeaderAccessor accessor = StompHeaderAccessor.create(StompCommand.MESSAGE); - accessor.setSessionId(sessionId); - accessor.setDestination("/sub/chatroom/" + chatroomId); - messagingTemplate.convertAndSend( - "/sub/chatroom/" + chatroomId, "해당 채팅방은 한 명만 남은 채팅방입니다!", accessor.getMessageHeaders()); + private String translationDivide(Chatroom chatroom, String settingLanguage, Member exitMember) { + + String baseMessage = "📢 "; + ResourceBundle resourceBundle; + String chatroomName = chatroom.getName(); + baseMessage += "(IN CHATROOM, " + chatroomName + ")"; + resourceBundle = + ResourceBundle.getBundle("notification.whenGroupChatroomAlone", Locale.getDefault()); + String messageSuffix = resourceBundle.getString(settingLanguage.toUpperCase()); + baseMessage += messageSuffix; + return baseMessage; + } + + public void notificate(Chatroom chatroom, Member exitMember) { + + Set members = chatroom.getMembers(); + Member member = + members.stream() + .findFirst() + .orElseThrow(() -> new NoSuchElementException("Member not found")); + + String settingLanguage = member.getSettingLanguage(); + List notificationTokens = member.getNotificationTokens(); + + String notificationMessage = translationDivide(chatroom, settingLanguage, exitMember); + + for (NotificationToken notificationToken : notificationTokens) { + Notification notification = new Notification(); + notification.setNotificationToken(notificationToken); + notification.setType(NotificationType.CHATROOM); + notification.setCreated(LocalDateTime.now()); + notification.setMessage(notificationMessage); + notificationToken.getNotifications().add(notification); + + notificationService.sendPushNotification( + notificationToken.getPushToken(), notification.getCreated(), notificationMessage); + } } } diff --git a/src/main/java/com/dife/api/model/Chat.java b/src/main/java/com/dife/api/model/Chat.java index cc7f1bb8..d1ebe20d 100644 --- a/src/main/java/com/dife/api/model/Chat.java +++ b/src/main/java/com/dife/api/model/Chat.java @@ -41,6 +41,8 @@ public class Chat implements TranslateTable { private LocalDateTime created; + private Boolean isOtherRead = false; + @Override public String getTextToTranslate() { return message; diff --git a/src/main/java/com/dife/api/model/dto/ChatResponseDto.java b/src/main/java/com/dife/api/model/dto/ChatResponseDto.java index af9f1940..2f94551c 100644 --- a/src/main/java/com/dife/api/model/dto/ChatResponseDto.java +++ b/src/main/java/com/dife/api/model/dto/ChatResponseDto.java @@ -25,4 +25,6 @@ public class ChatResponseDto { private List imgCode; private LocalDateTime created; + + private Boolean isOtherRead; } diff --git a/src/main/java/com/dife/api/repository/BookmarkRepository.java b/src/main/java/com/dife/api/repository/BookmarkRepository.java index a7e7912b..1277e639 100644 --- a/src/main/java/com/dife/api/repository/BookmarkRepository.java +++ b/src/main/java/com/dife/api/repository/BookmarkRepository.java @@ -14,9 +14,13 @@ public interface BookmarkRepository extends JpaRepository { @Query( - "SELECT b FROM Bookmark b JOIN b.member m JOIN m.chatrooms c WHERE m = :member AND c.id = :chatroomId") - List findBookmarksByMemberAndChatroomId( - @Param("chatroomId") Long chatroomId, @Param("member") Member member); + "SELECT b FROM Bookmark b " + + "JOIN b.member m " + + "JOIN Chatroom cr ON cr.id = :chatroomId " + + "JOIN cr.chats c " + + "WHERE m = :member AND b.message = c.message") + List findBookmarksByMemberAndChatroom( + @Param("member") Member member, @Param("chatroomId") Long chatroomId); List findAllByMember(Member member); diff --git a/src/main/java/com/dife/api/service/BookmarkService.java b/src/main/java/com/dife/api/service/BookmarkService.java index 15fe6be4..55ede5ba 100644 --- a/src/main/java/com/dife/api/service/BookmarkService.java +++ b/src/main/java/com/dife/api/service/BookmarkService.java @@ -8,6 +8,7 @@ import com.dife.api.model.dto.BookmarkResponseDto; import com.dife.api.repository.*; import java.util.List; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.modelmapper.ModelMapper; @@ -53,16 +54,16 @@ public List getChatroomBookmarks(Long chatroomId, String me Chatroom chatroom = chatroomRepository.findById(chatroomId).orElseThrow(ChatroomNotFoundException::new); + if (!chatroom.getMembers().contains(member)) { + throw new BookmarkNotFoundException(); + } - if (chatroom.getMembers().contains(member)) { - List bookmarks = - bookmarkRepository.findBookmarksByMemberAndChatroomId(chatroomId, member); + List bookmarks = + bookmarkRepository.findBookmarksByMemberAndChatroom(member, chatroomId); - return bookmarks.stream() - .map(b -> modelMapper.map(b, BookmarkResponseDto.class)) - .collect(toList()); - } - throw new BookmarkNotFoundException(); + return bookmarks.stream() + .map(b -> modelMapper.map(b, BookmarkResponseDto.class)) + .collect(Collectors.toList()); } public BookmarkResponseDto createBookmark( diff --git a/src/main/java/com/dife/api/service/ChatService.java b/src/main/java/com/dife/api/service/ChatService.java index 4e0276b1..4800d1b3 100644 --- a/src/main/java/com/dife/api/service/ChatService.java +++ b/src/main/java/com/dife/api/service/ChatService.java @@ -1,5 +1,8 @@ package com.dife.api.service; +import static com.dife.api.model.ChatroomType.GROUP; +import static com.dife.api.model.ChatroomType.SINGLE; + import com.dife.api.exception.ChatroomException; import com.dife.api.exception.ChatroomNotFoundException; import com.dife.api.exception.MemberNotFoundException; @@ -192,35 +195,49 @@ public void exit(ChatRequestDto dto, SimpMessageHeaderAccessor headerAccessor) chatroomRepository .findById(dto.getChatroomId()) .orElseThrow(ChatroomNotFoundException::new); - ChatroomSetting setting = chatroom.getChatroomSetting(); + Member member = memberService.getMemberEntityById(dto.getMemberId()); + if (chatroom.getChatroomType() == SINGLE) { + handleExit(dto, headerAccessor, chatroom, member); + return; + } + + ChatroomSetting originalSetting = chatroom.getChatroomSetting(); + + handleExit(dto, headerAccessor, chatroom, member); + + chatroom.setChatroomSetting(originalSetting); + chatroomRepository.save(chatroom); + } + + private void handleExit( + ChatRequestDto dto, + SimpMessageHeaderAccessor headerAccessor, + Chatroom chatroom, + Member member) + throws JsonProcessingException { + Long chatroomId = dto.getChatroomId(); String sessionId = headerAccessor.getSessionId(); if (!chatroom.getMembers().contains(member)) { - disconnectHandler.disconnect(chatroom.getId(), sessionId); + disconnectHandler.disconnect(chatroomId, sessionId); return; } - String username = (String) headerAccessor.getSessionAttributes().get("username"); - dto.setUsername(username); - if (!disconnectHandler.isExitDisconnectChecked(chatroom, sessionId)) return; - chatServiceFacade.decrease(chatroomId); + if (chatroom.getChatroomType() == GROUP) chatServiceFacade.decrease(chatroomId); chatroom.getMembers().remove(member); disconnectHandler.disconnect(chatroomId, sessionId); - String exitMessage = username + "님이 퇴장하셨습니다!"; + String exitMessage = member.getUsername() + "님이 퇴장하셨습니다!"; Chat chat = saveChat(member, chatroom, exitMessage); redisPublisher.publish(dealDto(chat, member, chatroom)); - notificationHandler.isAlone(chatroom, sessionId); - - chatroom.setChatroomSetting(setting); - chatroomRepository.save(chatroom); + notificationHandler.isAlone(chatroom, member); } public Chat saveChat(Member member, Chatroom chatroom, String message) { diff --git a/src/main/java/com/dife/api/service/ChatroomService.java b/src/main/java/com/dife/api/service/ChatroomService.java index 26efe921..a63550f8 100644 --- a/src/main/java/com/dife/api/service/ChatroomService.java +++ b/src/main/java/com/dife/api/service/ChatroomService.java @@ -387,7 +387,6 @@ public ChatResponseDto getChat(Long chatroomId, Long chatId, String memberEmail) Chatroom chatroom = chatroomRepository.findById(chatroomId).orElseThrow(ChatroomNotFoundException::new); - if (!chatroom.getMembers().contains(member)) throw new ChatroomException("소속회원만이 채팅 불러올 수 있음"); Chat chat = @@ -395,6 +394,8 @@ public ChatResponseDto getChat(Long chatroomId, Long chatId, String memberEmail) .findByChatroomIdAndId(chatroomId, chatId) .orElseThrow(ChatNotFoundException::new); + if (!chat.getMember().equals(member) && !chat.getIsOtherRead()) chat.setIsOtherRead(true); + ChatResponseDto responseDto = modelMapper.map(chat, ChatResponseDto.class); if (chatroom.getChatroomType() == ChatroomType.GROUP) diff --git a/src/main/java/com/dife/api/service/MemberService.java b/src/main/java/com/dife/api/service/MemberService.java index 71336449..0bcb32de 100644 --- a/src/main/java/com/dife/api/service/MemberService.java +++ b/src/main/java/com/dife/api/service/MemberService.java @@ -241,8 +241,6 @@ public MemberResponseDto getMember(String email) { Member member = memberRepository.findByEmail(email).orElseThrow(MemberNotFoundException::new); MemberResponseDto responseDto = memberModelMapper.map(member, MemberResponseDto.class); - if (member.getProfileImg() != null) - responseDto.setProfileImg(modelMapper.map(member.getProfileImg(), File.class)); return responseDto; } @@ -257,9 +255,6 @@ public MemberResponseDto getMemberById(Long id, String memberEmail) { MemberResponseDto responseDto = memberModelMapper.map(findMember, MemberResponseDto.class); responseDto.setIsLiked(likeService.isLikeListMember(member, findMember)); - - if (member.getProfileImg() != null) - responseDto.setProfileImg(modelMapper.map(member.getProfileImg(), File.class)); return responseDto; } @@ -598,8 +593,6 @@ public List getSearchMembers(String keyword, String memberEma private MemberResponseDto getMemberResponseDto(Member member, Member currentMember) { MemberResponseDto responseDto = memberModelMapper.map(member, MemberResponseDto.class); responseDto.setIsLiked(likeService.isLikeListMember(currentMember, member)); - if (member.getProfileImg() != null) - responseDto.setProfileImg(modelMapper.map(member.getProfileImg(), File.class)); return responseDto; } diff --git a/src/main/resources/db/changelog/v1.0/v1.0.4.xml b/src/main/resources/db/changelog/v1.0/v1.0.4.xml new file mode 100644 index 00000000..2b5a1c06 --- /dev/null +++ b/src/main/resources/db/changelog/v1.0/v1.0.4.xml @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/notification/whenSingleChatroomAlone.properties b/src/main/resources/notification/whenSingleChatroomAlone.properties new file mode 100644 index 00000000..df956c8a --- /dev/null +++ b/src/main/resources/notification/whenSingleChatroomAlone.properties @@ -0,0 +1,5 @@ +EN = You are the only one left in the chatroom +KO = \uCC44\uD305\uBC29\uC5D0 \uD63C\uC790 \uB0A8\uC558\uC2B5\uB2C8\uB2E4 +ZH = \u7684\u804A\u5929\u623F\u95F4\u91CC\u72EC\u81EA\u7559\u4E0B\u4E86 +JA = \u3068\u306E\u30C1\u30E3\u30C3\u30C8\u30EB\u30FC\u30E0\u306B\u4E00\u4EBA\u3060\u3051\u6B8B\u3063\u3066\u3044\u307E\u3059 +ES = \u00A1Te has quedado solo en la sala de chat con