From 445fd45a5587ceec41ba677144e73c6510db6d22 Mon Sep 17 00:00:00 2001 From: JaeSeo Yang <96044622+psychology50@users.noreply.github.com> Date: Wed, 22 Jan 2025 15:52:59 +0900 Subject: [PATCH 1/9] fix: add notify_enabled field into the chat-room-detail --- .../pennyway/domain/domains/chatroom/dto/ChatRoomDetail.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pennyway-domain/domain-rdb/src/main/java/kr/co/pennyway/domain/domains/chatroom/dto/ChatRoomDetail.java b/pennyway-domain/domain-rdb/src/main/java/kr/co/pennyway/domain/domains/chatroom/dto/ChatRoomDetail.java index adb507828..2ac014cd6 100644 --- a/pennyway-domain/domain-rdb/src/main/java/kr/co/pennyway/domain/domains/chatroom/dto/ChatRoomDetail.java +++ b/pennyway-domain/domain-rdb/src/main/java/kr/co/pennyway/domain/domains/chatroom/dto/ChatRoomDetail.java @@ -10,6 +10,7 @@ public record ChatRoomDetail( Integer password, LocalDateTime createdAt, boolean isAdmin, - int participantCount + int participantCount, + boolean isNotifyEnabled ) { } From 23f91fd27934700291554f0a6afa2e3b264d23f9 Mon Sep 17 00:00:00 2001 From: JaeSeo Yang <96044622+psychology50@users.noreply.github.com> Date: Wed, 22 Jan 2025 15:53:38 +0900 Subject: [PATCH 2/9] fix: add notify_enabled select field when chat-member select query --- .../repository/ChatRoomCustomRepositoryImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pennyway-domain/domain-rdb/src/main/java/kr/co/pennyway/domain/domains/chatroom/repository/ChatRoomCustomRepositoryImpl.java b/pennyway-domain/domain-rdb/src/main/java/kr/co/pennyway/domain/domains/chatroom/repository/ChatRoomCustomRepositoryImpl.java index f48321432..25af60379 100644 --- a/pennyway-domain/domain-rdb/src/main/java/kr/co/pennyway/domain/domains/chatroom/repository/ChatRoomCustomRepositoryImpl.java +++ b/pennyway-domain/domain-rdb/src/main/java/kr/co/pennyway/domain/domains/chatroom/repository/ChatRoomCustomRepositoryImpl.java @@ -45,6 +45,7 @@ public List findChatRoomsByUserId(Long userId) { final String CHAT_ROOM_ID = "chat_room_id"; final String MEMBER_COUNT = "member_count"; final String IS_ADMIN = "is_admin"; + final String NOTIFY_ENABLED = "notify_enabled"; // EntityPath 정의 EntityPath Chat_MEMBER_ENTITY_PATH = new EntityPathBase<>(ChatMember.class, "chat_member"); @@ -67,7 +68,8 @@ public List findChatRoomsByUserId(Long userId) { Expressions.booleanTemplate( "MAX(CASE WHEN user_id = {0} AND role = '0' THEN true ELSE false END)", userId - ).as(IS_ADMIN) + ).as(IS_ADMIN), + Expressions.booleanPath(Chat_MEMBER_ENTITY_PATH, "notify_enabled").as(NOTIFY_ENABLED) ) .from(Chat_MEMBER_ENTITY_PATH) .where(Expressions.dateTimePath(LocalDateTime.class, Chat_MEMBER_ENTITY_PATH, "deleted_at").isNull()) @@ -88,7 +90,8 @@ public List findChatRoomsByUserId(Long userId) { "createdAt" ), Expressions.booleanPath(ROOM_STATS, IS_ADMIN), - Expressions.numberPath(Integer.class, ROOM_STATS, MEMBER_COUNT) + Expressions.numberPath(Integer.class, ROOM_STATS, MEMBER_COUNT), + Expressions.booleanPath(ROOM_STATS, NOTIFY_ENABLED) )) .from(CHAT_ROOM_ENTITY_PATH) .innerJoin(myRoomsQuery, MY_ROOMS) @@ -173,7 +176,8 @@ public Slice findChatRooms(Long userId, String target, Pageable "createdAt" ), Expressions.constant(false), - Expressions.numberPath(Integer.class, CM_COUNT, MEMBER_COUNT) + Expressions.numberPath(Integer.class, CM_COUNT, MEMBER_COUNT), + Expressions.constant(false) )) .from(CHAT_ROOM_ENTITY_PATH) .innerJoin(eligibleRoomsQuery, CM) From 87c84ab1663d0a625ac8777f76b538714e7f274c Mon Sep 17 00:00:00 2001 From: JaeSeo Yang <96044622+psychology50@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:22:15 +0900 Subject: [PATCH 3/9] feat: add chat-room detail response dto for v2 --- .../api/apis/chat/dto/ChatRoomRes.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/dto/ChatRoomRes.java b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/dto/ChatRoomRes.java index 5e8d7c7b9..0cba62af2 100644 --- a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/dto/ChatRoomRes.java +++ b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/dto/ChatRoomRes.java @@ -100,6 +100,48 @@ public static Detail from(ChatRoomRes.Info info) { } } + @Schema(description = "채팅방 상세 정보 ver.2") + public record Detailv2( + @Schema(description = "채팅방 ID", type = "long") + Long id, + @Schema(description = "채팅방 제목") + String title, + @Schema(description = "채팅방 설명") + String description, + @Schema(description = "채팅방 배경 이미지 URL") + String backgroundImageUrl, + @Schema(description = "채팅방 알림 설정") + boolean isNotifyEnabled, + @Schema(description = "채팅방 비공개 여부") + boolean isPrivate, + @Schema(description = "어드민 여부. 채팅방의 관리자라면 true, 아니라면 false") + boolean isAdmin, + @Schema(description = "채팅방 참여자 수") + int participantCount, + @Schema(description = "채팅방 개설일") + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime createdAt, + @Schema(description = "마지막 메시지 정보. 없을 경우 null이 반환된다.") + ChatRes.ChatDetail lastMessage, + @Schema(description = "읽지 않은 메시지 수. 100 이상의 값을 가지면, 100으로 표시된다.") + long unreadMessageCount + ) { + public Detailv2(Long id, String title, String description, String backgroundImageUrl, boolean isNotifyEnabled, boolean isPrivate, boolean isAdmin, int participantCount, LocalDateTime createdAt, ChatRes.ChatDetail lastMessage, long unreadMessageCount) { + this.id = id; + this.title = title; + this.description = Objects.toString(description, ""); + this.backgroundImageUrl = Objects.toString(backgroundImageUrl, ""); + this.isNotifyEnabled = isNotifyEnabled; + this.isPrivate = isPrivate; + this.isAdmin = isAdmin; + this.participantCount = participantCount; + this.createdAt = createdAt; + this.lastMessage = lastMessage; + this.unreadMessageCount = (unreadMessageCount > 100) ? 100 : unreadMessageCount; + } + } + @Schema(description = "채팅방 정보 (어드민용)") public record AdminView( @Schema(description = "채팅방 ID", type = "long") From 1d2217bb3ba081d60ec7769621f55c17073c6c61 Mon Sep 17 00:00:00 2001 From: JaeSeo Yang <96044622+psychology50@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:22:51 +0900 Subject: [PATCH 4/9] feat: add method to map entity to detail dto v2 --- .../api/apis/chat/mapper/ChatRoomMapper.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/mapper/ChatRoomMapper.java b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/mapper/ChatRoomMapper.java index 3877ac73d..d5075fb34 100644 --- a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/mapper/ChatRoomMapper.java +++ b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/mapper/ChatRoomMapper.java @@ -70,6 +70,30 @@ public static List toChatRoomResDetails(List toChatRoomResDetailsV2(List details) { + List responses = new ArrayList<>(); + + for (ChatRoomRes.Info info : details) { + responses.add( + new ChatRoomRes.Detailv2( + info.chatRoom().id(), + info.chatRoom().title(), + info.chatRoom().description(), + info.chatRoom().backgroundImageUrl(), + info.chatRoom().isNotifyEnabled(), + info.chatRoom().password() != null, + info.chatRoom().isAdmin(), + info.chatRoom().participantCount(), + info.chatRoom().createdAt(), + info.lastMessage(), + info.unreadMessageCount() + ) + ); + } + + return responses; + } + public static ChatRoomRes.Detail toChatRoomResDetail(ChatRoom chatRoom, ChatRes.ChatDetail lastMessage, boolean isAdmin, int participantCount, long unreadMessageCount) { return ChatRoomRes.Detail.of(chatRoom, lastMessage, isAdmin, participantCount, unreadMessageCount); } From 6ce943a6758ca130be44af892b331d5e4a02cd19 Mon Sep 17 00:00:00 2001 From: JaeSeo Yang <96044622+psychology50@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:23:06 +0900 Subject: [PATCH 5/9] feat: add v2 usecase --- .../co/pennyway/api/apis/chat/usecase/ChatRoomUseCase.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/usecase/ChatRoomUseCase.java b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/usecase/ChatRoomUseCase.java index 281c0c86b..cc68a720d 100644 --- a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/usecase/ChatRoomUseCase.java +++ b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/usecase/ChatRoomUseCase.java @@ -40,12 +40,19 @@ public ChatRoomRes.AdminView getChatRoom(Long chatRoomId) { return ChatRoomMapper.toChatRoomResAdminView(chatRoom); } + @Deprecated(since = "2025-01-22") public List getChatRooms(Long userId) { List chatRooms = chatRoomSearchService.readChatRooms(userId); return ChatRoomMapper.toChatRoomResDetails(chatRooms); } + public List getChatRoomDetails(Long userId) { + List chatRooms = chatRoomSearchService.readChatRooms(userId); + + return ChatRoomMapper.toChatRoomResDetailsV2(chatRooms); + } + public ChatRoomRes.RoomWithParticipants getChatRoomWithParticipants(Long userId, Long chatRoomId) { return chatRoomWithParticipantsSearchService.execute(userId, chatRoomId); } From 74a5aaf7873ec363327bda1e560460bb04a88ebb Mon Sep 17 00:00:00 2001 From: JaeSeo Yang <96044622+psychology50@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:23:46 +0900 Subject: [PATCH 6/9] docs: write about getting chat room v2 api swagger --- .../api/apis/chat/api/ChatRoomApiV2.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApiV2.java diff --git a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApiV2.java b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApiV2.java new file mode 100644 index 000000000..9c7f4de71 --- /dev/null +++ b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApiV2.java @@ -0,0 +1,23 @@ +package kr.co.pennyway.api.apis.chat.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.SchemaProperty; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import kr.co.pennyway.api.apis.chat.dto.ChatRoomRes; +import kr.co.pennyway.api.common.security.authentication.SecurityUserDetails; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "[임시 채팅방 API]", description = "버전 관리를 위한 임시 채팅방 API, 추후 [채팅방 API]로 통합될 예정입니다.") +public interface ChatRoomApiV2 { + @Operation(summary = "가입한 채팅방 목록 조회", method = "GET", description = "사용자가 가입한 채팅방 목록을 조회하며, 정렬 순서는 보장하지 않는다. 최근 활성화된 채팅방의 순서를 지정할 방법에 대해 추가 개선이 필요한 API이므로, 추후 기능이 일부 수정될 수도 있다.") + @Parameter(name = "summary", description = "채팅방 요약 정보 조회 여부. true로 설정하면 채팅방의 상세 정보가 chatRoomIds 필드만 반환된다. (default=false)", example = "false") + @ApiResponse(responseCode = "200", description = "가입한 채팅방 목록 조회 성공", content = @Content(schemaProperties = @SchemaProperty(name = "chatRooms", array = @ArraySchema(schema = @Schema(implementation = ChatRoomRes.Detailv2.class))))) + ResponseEntity getMyChatRooms(@RequestParam(name = "summary", required = false, defaultValue = "false") boolean isSummary, @AuthenticationPrincipal SecurityUserDetails user); +} From 79fd995f861c29a4c3443f974090fcad70c2517c Mon Sep 17 00:00:00 2001 From: JaeSeo Yang <96044622+psychology50@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:24:08 +0900 Subject: [PATCH 7/9] feat: impl v2 chat room controller --- .../chat/controller/ChatRoomControllerV2.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/controller/ChatRoomControllerV2.java diff --git a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/controller/ChatRoomControllerV2.java b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/controller/ChatRoomControllerV2.java new file mode 100644 index 000000000..a927897c2 --- /dev/null +++ b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/controller/ChatRoomControllerV2.java @@ -0,0 +1,35 @@ +package kr.co.pennyway.api.apis.chat.controller; + +import kr.co.pennyway.api.apis.chat.api.ChatRoomApiV2; +import kr.co.pennyway.api.apis.chat.usecase.ChatRoomUseCase; +import kr.co.pennyway.api.common.response.SuccessResponse; +import kr.co.pennyway.api.common.security.authentication.SecurityUserDetails; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/v3/chat-rooms") +public class ChatRoomControllerV2 implements ChatRoomApiV2 { + private static final String CHAT_ROOMS = "chatRooms"; + private final ChatRoomUseCase chatRoomUseCase; + + @Override + @GetMapping("/me") + @PreAuthorize("isAuthenticated()") + public ResponseEntity getMyChatRooms(@RequestParam(name = "summary", required = false, defaultValue = "false") boolean isSummary, @AuthenticationPrincipal SecurityUserDetails user) { + if (isSummary) { + return ResponseEntity.ok(SuccessResponse.from(CHAT_ROOMS, chatRoomUseCase.readJoinedChatRoomIds(user.getUserId()))); + } + + return ResponseEntity.ok(SuccessResponse.from(CHAT_ROOMS, chatRoomUseCase.getChatRoomDetails(user.getUserId()))); + } +} From df753a87d21c05e2f4c8155c4eed7b22354ebd45 Mon Sep 17 00:00:00 2001 From: JaeSeo Yang <96044622+psychology50@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:24:37 +0900 Subject: [PATCH 8/9] fix: deprecate v2 get-my-chat-rooms api --- .../main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApi.java b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApi.java index fb3c4b7fe..7f17579a6 100644 --- a/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApi.java +++ b/pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApi.java @@ -29,7 +29,7 @@ public interface ChatRoomApi { @ApiResponse(responseCode = "200", description = "채팅방 생성 성공", content = @Content(schemaProperties = @SchemaProperty(name = "chatRoom", schema = @Schema(implementation = ChatRoomRes.Detail.class)))) ResponseEntity createChatRoom(@RequestBody ChatRoomReq.Create request, @AuthenticationPrincipal SecurityUserDetails user); - @Operation(summary = "가입한 채팅방 목록 조회", method = "GET", description = "사용자가 가입한 채팅방 목록을 조회하며, 정렬 순서는 보장하지 않는다. 최근 활성화된 채팅방의 순서를 지정할 방법에 대해 추가 개선이 필요한 API이므로, 추후 기능이 일부 수정될 수도 있다.") + @Operation(summary = "가입한 채팅방 목록 조회", method = "GET", description = "사용자가 가입한 채팅방 목록을 조회하며, 정렬 순서는 보장하지 않는다. 최근 활성화된 채팅방의 순서를 지정할 방법에 대해 추가 개선이 필요한 API이므로, 추후 기능이 일부 수정될 수도 있다.", deprecated = true) @Parameter(name = "summary", description = "채팅방 요약 정보 조회 여부. true로 설정하면 채팅방의 상세 정보가 chatRoomIds 필드만 반환된다. (default=false)", example = "false") @ApiResponse(responseCode = "200", description = "가입한 채팅방 목록 조회 성공", content = @Content(schemaProperties = @SchemaProperty(name = "chatRooms", array = @ArraySchema(schema = @Schema(implementation = ChatRoomRes.Detail.class))))) ResponseEntity getMyChatRooms(@RequestParam(name = "summary", required = false, defaultValue = "false") boolean query, @AuthenticationPrincipal SecurityUserDetails user); From bddfbab626b94c3c4cf681f60126f50adbd5b8b8 Mon Sep 17 00:00:00 2001 From: JaeSeo Yang <96044622+psychology50@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:43:50 +0900 Subject: [PATCH 9/9] test: fix given clauses for chat-room-detail --- .../apis/chat/service/ChatRoomSearchServiceTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pennyway-app-external-api/src/test/java/kr/co/pennyway/api/apis/chat/service/ChatRoomSearchServiceTest.java b/pennyway-app-external-api/src/test/java/kr/co/pennyway/api/apis/chat/service/ChatRoomSearchServiceTest.java index 923fd0a60..ad45518ff 100644 --- a/pennyway-app-external-api/src/test/java/kr/co/pennyway/api/apis/chat/service/ChatRoomSearchServiceTest.java +++ b/pennyway-app-external-api/src/test/java/kr/co/pennyway/api/apis/chat/service/ChatRoomSearchServiceTest.java @@ -45,8 +45,8 @@ void successReadChatRooms() { // given Long userId = 1L; List chatRooms = List.of( - new ChatRoomDetail(1L, "Room1", "", "", 123456, LocalDateTime.now(), true, 2), - new ChatRoomDetail(2L, "Room2", "", "", null, LocalDateTime.now(), false, 2) + new ChatRoomDetail(1L, "Room1", "", "", 123456, LocalDateTime.now(), true, 2, true), + new ChatRoomDetail(2L, "Room2", "", "", null, LocalDateTime.now(), false, 2, true) ); given(chatRoomService.readChatRoomsByUserId(userId)).willReturn(chatRooms); @@ -101,8 +101,8 @@ void continueProcessingOnError() { // given Long userId = 1L; List chatRooms = List.of( - new ChatRoomDetail(1L, "Room1", "", "", 123456, LocalDateTime.now(), true, 2), - new ChatRoomDetail(2L, "Room2", "", "", null, LocalDateTime.now(), false, 2) + new ChatRoomDetail(1L, "Room1", "", "", 123456, LocalDateTime.now(), true, 2, true), + new ChatRoomDetail(2L, "Room2", "", "", null, LocalDateTime.now(), false, 2, true) ); given(chatRoomService.readChatRoomsByUserId(userId)).willReturn(chatRooms); @@ -124,7 +124,7 @@ void verifyServiceCallOrder() { // given Long userId = 1L; List chatRooms = List.of( - new ChatRoomDetail(1L, "Room1", "", "", 123456, LocalDateTime.now(), true, 2) + new ChatRoomDetail(1L, "Room1", "", "", 123456, LocalDateTime.now(), true, 2, true) ); InOrder inOrder = inOrder(chatRoomService, chatMessageStatusService, chatMessageService, chatMessageService);