-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ✨ Get Chat Member Informations By Batch (#189)
* feat: add read method in to the chat_member_search_service * feat: add api_error_code & exception * feat: chat_member response mapper * feat: get chat_member list usecase * docs: get chat member swagger * feat: impl controller * fix: query param @not_null -> @not_empty * test: controller unit test * test: integration test * fix: 혼동을 주는 member_id -> user_id로 수정 및 멤버 정보 조회 시 chat_member_id를 사용하도록 쿼리 수정 * docs: 채팅방 멤버 조회 시, 경고 사항 스웨거에 추가 * test: 테스트 시, 사용자 아이디 -> 채팅방 멤버 아이디로 수정
- Loading branch information
1 parent
4fb271b
commit e0f21fa
Showing
13 changed files
with
380 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
...-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/mapper/ChatMemberMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package kr.co.pennyway.api.apis.chat.mapper; | ||
|
||
import kr.co.pennyway.api.apis.chat.dto.ChatMemberRes; | ||
import kr.co.pennyway.common.annotation.Mapper; | ||
import kr.co.pennyway.domain.domains.member.domain.ChatMember; | ||
|
||
import java.util.List; | ||
|
||
@Mapper | ||
public final class ChatMemberMapper { | ||
public static List<ChatMemberRes.Detail> toChatMemberResDetail(List<ChatMember> chatMembers) { | ||
return chatMembers.stream() | ||
.map(chatMember -> ChatMemberRes.Detail.from(chatMember, false)) | ||
.toList(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
...pp-external-api/src/main/java/kr/co/pennyway/api/apis/chat/usecase/ChatMemberUseCase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,37 @@ | ||
package kr.co.pennyway.api.apis.chat.usecase; | ||
|
||
import kr.co.pennyway.api.apis.chat.dto.ChatMemberRes; | ||
import kr.co.pennyway.api.apis.chat.dto.ChatRoomRes; | ||
import kr.co.pennyway.api.apis.chat.mapper.ChatMemberMapper; | ||
import kr.co.pennyway.api.apis.chat.mapper.ChatRoomMapper; | ||
import kr.co.pennyway.api.apis.chat.service.ChatMemberJoinService; | ||
import kr.co.pennyway.api.apis.chat.service.ChatMemberSearchService; | ||
import kr.co.pennyway.common.annotation.UseCase; | ||
import kr.co.pennyway.domain.domains.chatroom.domain.ChatRoom; | ||
import kr.co.pennyway.domain.domains.member.domain.ChatMember; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.apache.commons.lang3.tuple.Pair; | ||
|
||
import java.util.List; | ||
import java.util.Set; | ||
|
||
@Slf4j | ||
@UseCase | ||
@RequiredArgsConstructor | ||
public class ChatMemberUseCase { | ||
private final ChatMemberJoinService chatMemberJoinService; | ||
private final ChatMemberSearchService chatMemberSearchService; | ||
|
||
public ChatRoomRes.Detail joinChatRoom(Long userId, Long chatRoomId, Integer password) { | ||
Pair<ChatRoom, Integer> chatRoom = chatMemberJoinService.execute(userId, chatRoomId, password); | ||
|
||
return ChatRoomMapper.toChatRoomResDetail(chatRoom.getLeft(), false, chatRoom.getRight()); | ||
} | ||
|
||
public List<ChatMemberRes.Detail> readChatMembers(Long chatRoomId, Set<Long> chatMemberIds) { | ||
List<ChatMember> chatMembers = chatMemberSearchService.readChatMembers(chatRoomId, chatMemberIds); | ||
|
||
return ChatMemberMapper.toChatMemberResDetail(chatMembers); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
...yway-app-external-api/src/main/java/kr/co/pennyway/api/common/exception/ApiErrorCode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package kr.co.pennyway.api.common.exception; | ||
|
||
import kr.co.pennyway.common.exception.BaseErrorCode; | ||
import kr.co.pennyway.common.exception.CausedBy; | ||
import kr.co.pennyway.common.exception.ReasonCode; | ||
import kr.co.pennyway.common.exception.StatusCode; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum ApiErrorCode implements BaseErrorCode { | ||
// 400 Bad Request | ||
OVERFLOW_QUERY_PARAMETER(StatusCode.BAD_REQUEST, ReasonCode.INVALID_REQUEST, "쿼리 파라미터가 너무 많습니다."), | ||
; | ||
|
||
private final StatusCode statusCode; | ||
private final ReasonCode reasonCode; | ||
private final String message; | ||
|
||
@Override | ||
public CausedBy causedBy() { | ||
return CausedBy.of(statusCode, reasonCode); | ||
} | ||
|
||
@Override | ||
public String getExplainError() throws NoSuchFieldError { | ||
return message; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
...app-external-api/src/main/java/kr/co/pennyway/api/common/exception/ApiErrorException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package kr.co.pennyway.api.common.exception; | ||
|
||
import kr.co.pennyway.common.exception.CausedBy; | ||
import kr.co.pennyway.common.exception.GlobalErrorException; | ||
|
||
public class ApiErrorException extends GlobalErrorException { | ||
private final ApiErrorCode errorCode; | ||
|
||
public ApiErrorException(ApiErrorCode errorCode) { | ||
super(errorCode); | ||
this.errorCode = errorCode; | ||
} | ||
|
||
@Override | ||
public CausedBy causedBy() { | ||
return errorCode.causedBy(); | ||
} | ||
|
||
public String getExplainError() { | ||
return errorCode.getExplainError(); | ||
} | ||
} |
126 changes: 126 additions & 0 deletions
126
...rc/test/java/kr/co/pennyway/api/apis/chat/controller/ChatMemberBathGetControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package kr.co.pennyway.api.apis.chat.controller; | ||
|
||
import kr.co.pennyway.api.apis.chat.dto.ChatMemberRes; | ||
import kr.co.pennyway.api.apis.chat.usecase.ChatMemberUseCase; | ||
import kr.co.pennyway.api.config.supporter.WithSecurityMockUser; | ||
import kr.co.pennyway.domain.domains.member.type.ChatMemberRole; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; | ||
import org.springframework.boot.test.mock.mockito.MockBean; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.test.context.ActiveProfiles; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||
import org.springframework.test.web.servlet.setup.MockMvcBuilders; | ||
import org.springframework.web.context.WebApplicationContext; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.LongStream; | ||
|
||
import static org.mockito.BDDMockito.given; | ||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
@WebMvcTest(controllers = ChatMemberController.class) | ||
@ActiveProfiles("test") | ||
public class ChatMemberBathGetControllerTest { | ||
@Autowired | ||
private MockMvc mockMvc; | ||
|
||
@MockBean | ||
private ChatMemberUseCase chatMemberUseCase; | ||
|
||
@BeforeEach | ||
void setUp(WebApplicationContext webApplicationContext) { | ||
this.mockMvc = MockMvcBuilders | ||
.webAppContextSetup(webApplicationContext) | ||
.defaultRequest(MockMvcRequestBuilders.get("/**").with(csrf())) | ||
.build(); | ||
} | ||
|
||
@Test | ||
@DisplayName("채팅방 멤버 조회에 성공한다") | ||
@WithSecurityMockUser | ||
void successReadChatMembers() throws Exception { | ||
// given | ||
Long chatRoomId = 1L; | ||
Set<Long> memberIds = Set.of(1L, 2L, 3L); | ||
List<ChatMemberRes.Detail> expectedResponse = createMockMemberDetails(); | ||
|
||
given(chatMemberUseCase.readChatMembers(chatRoomId, memberIds)).willReturn(expectedResponse); | ||
|
||
// when & then | ||
mockMvc.perform(MockMvcRequestBuilders.get("/v2/chat-rooms/{chatRoomId}/chat-members", chatRoomId) | ||
.param("ids", "1,2,3") | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.data.chatMembers").isArray()) | ||
.andExpect(jsonPath("$.data.chatMembers.length()").value(3)) | ||
.andDo(print()); | ||
} | ||
|
||
@Test | ||
@DisplayName("50개를 초과하는 멤버 ID 요청 시 실패한다") | ||
@WithSecurityMockUser | ||
void failReadChatMembersWhenExceedLimit() throws Exception { | ||
// given | ||
Long chatRoomId = 1L; | ||
Set<Long> memberIds = LongStream.rangeClosed(1, 51) | ||
.boxed() | ||
.collect(Collectors.toSet()); | ||
|
||
// when & then | ||
mockMvc.perform(MockMvcRequestBuilders.get("/v2/chat-rooms/{chatRoomId}/chat-members", chatRoomId) | ||
.param("ids", memberIds.stream() | ||
.map(String::valueOf) | ||
.collect(Collectors.joining(","))) | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isBadRequest()) | ||
.andDo(print()); | ||
} | ||
|
||
@Test | ||
@DisplayName("ids가 null인 경우 실패한다 <400 Bad Request>") | ||
@WithSecurityMockUser | ||
void failReadChatMembersWhenIdsIsNull() throws Exception { | ||
// given | ||
Long chatRoomId = 1L; | ||
|
||
// when & then | ||
mockMvc.perform(MockMvcRequestBuilders.get("/v2/chat-rooms/{chatRoomId}/chat-members", chatRoomId) | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isBadRequest()) | ||
.andDo(print()); | ||
} | ||
|
||
@Test | ||
@DisplayName("ids가 빈 값일 경우 실패한다") | ||
@WithSecurityMockUser | ||
void failReadChatMembersWhenIdsIsEmpty() throws Exception { | ||
// given | ||
Long chatRoomId = 1L; | ||
|
||
// when & then | ||
mockMvc.perform(MockMvcRequestBuilders.get("/v2/chat-rooms/{chatRoomId}/chat-members", chatRoomId) | ||
.param("ids", "") | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isBadRequest()) | ||
.andDo(print()); | ||
} | ||
|
||
private List<ChatMemberRes.Detail> createMockMemberDetails() { | ||
return List.of( | ||
new ChatMemberRes.Detail(1L, "User1", ChatMemberRole.MEMBER, null, LocalDateTime.now()), | ||
new ChatMemberRes.Detail(2L, "User2", ChatMemberRole.MEMBER, null, LocalDateTime.now()), | ||
new ChatMemberRes.Detail(3L, "User3", ChatMemberRole.MEMBER, null, LocalDateTime.now()) | ||
); | ||
} | ||
} |
Oops, something went wrong.