From 946308d1dc92a8a45233e7ca467165e758b1358d Mon Sep 17 00:00:00 2001 From: amaran-th Date: Sun, 5 Nov 2023 05:14:31 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80/=EC=82=AD=EC=A0=9C=20=EC=8B=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=ED=95=9C=20=ED=96=89=EC=82=AC=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EB=A5=BC=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #823 --- .../java/com/emmsale/ScrapApiTest.java | 69 +++++++++++++++++-- .../java/com/emmsale/scrap/api/ScrapApi.java | 8 +-- .../application/ScrapCommandService.java | 16 ++++- 3 files changed, 81 insertions(+), 12 deletions(-) diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java index af0f65739..c8ada91e4 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java @@ -1,7 +1,6 @@ package com.emmsale; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; @@ -32,6 +31,31 @@ @WebMvcTest(ScrapApi.class) class ScrapApiTest extends MockMvcTestHelper { + final ResponseFieldsSnippet SCRAPPED_EVENT_RESPONSE_FIELDS = PayloadDocumentation.responseFields( + fieldWithPath("id").type(JsonFieldType.NUMBER).description("행사 식별자"), + fieldWithPath("name").type(JsonFieldType.STRING) + .description("행사 이름"), + fieldWithPath("informationUrl").type(JsonFieldType.STRING) + .description("행사 상세정보 url"), + fieldWithPath("startDate").type(JsonFieldType.STRING) + .description("행사 시작 일자"), + fieldWithPath("endDate").type(JsonFieldType.STRING).description("행사 종료 일자"), + fieldWithPath("applyStartDate").type(JsonFieldType.STRING) + .description("행사 신청 시작 일자(nullable)"), + fieldWithPath("applyEndDate").type(JsonFieldType.STRING) + .description("행사 신청 종료 일자(nullable)"), + fieldWithPath("location").type(JsonFieldType.STRING).description("행사 장소"), + fieldWithPath("tags[]").type(JsonFieldType.ARRAY).description("행사 태그들"), + fieldWithPath("thumbnailUrl").type(JsonFieldType.STRING) + .description("행사 섬네일 이미지 Url(포스터)"), + fieldWithPath("type").type(JsonFieldType.STRING) + .description("행사의 분류"), + fieldWithPath("imageUrls[]").description("행사의 상세 정보 이미지 URL들").optional(), + fieldWithPath("organization").description("행사 주최기관"), + fieldWithPath("paymentType").description("행사의 유무료 여부(유료,무료,유무료)"), + fieldWithPath("eventMode").description("행사의 온/오프라인 여부(온라인,오프라인,온오프라인)") + ); + @Test @DisplayName("스크랩 목록을 성공적으로 조회하면 200 OK를 반환한다.") void findAllScraps() throws Exception { @@ -129,13 +153,29 @@ void append() throws Exception { final long eventId = 1L; final ScrapRequest request = new ScrapRequest(eventId); - + final EventResponse expectedScrapResponse = new EventResponse( + 1L, + "인프콘 2023", + "https://aaa", + LocalDateTime.parse("2023-06-03T12:00:00"), + LocalDateTime.parse("2023-09-03T12:00:00"), + LocalDateTime.parse("2023-09-01T00:00:00"), + LocalDateTime.parse("2023-09-02T23:59:59"), + "코엑스", + List.of("백엔드", "프론트엔드", "안드로이드", "IOS", "AI"), + "image0.jpg", + EventType.CONFERENCE.name(), + List.of("image1.jpg", "image2.jpg", "image3.jpg"), + "인프런", + PaymentType.PAID.getValue(), + EventMode.ONLINE.getValue() + ); final RequestFieldsSnippet requestFields = requestFields( fieldWithPath("eventId").description("스크랩할 이벤트 id") ); //when - doNothing().when(scrapCommandService).append(any(), any()); + when(scrapCommandService.append(any(), any())).thenReturn(expectedScrapResponse); //then mockMvc.perform(post("/scraps") @@ -143,7 +183,7 @@ void append() throws Exception { .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isCreated()) - .andDo(document("append-scrap", requestFields)); + .andDo(document("append-scrap", requestFields, SCRAPPED_EVENT_RESPONSE_FIELDS)); } @Test @@ -151,14 +191,31 @@ void append() throws Exception { void deleteScrap() throws Exception { //given final long eventId = 1L; + final EventResponse expectedScrapResponse = new EventResponse( + 1L, + "인프콘 2023", + "https://aaa", + LocalDateTime.parse("2023-06-03T12:00:00"), + LocalDateTime.parse("2023-09-03T12:00:00"), + LocalDateTime.parse("2023-09-01T00:00:00"), + LocalDateTime.parse("2023-09-02T23:59:59"), + "코엑스", + List.of("백엔드", "프론트엔드", "안드로이드", "IOS", "AI"), + "image0.jpg", + EventType.CONFERENCE.name(), + List.of("image1.jpg", "image2.jpg", "image3.jpg"), + "인프런", + PaymentType.PAID.getValue(), + EventMode.ONLINE.getValue() + ); //when - doNothing().when(scrapCommandService).deleteScrap(any(), any()); + when(scrapCommandService.deleteScrap(any(), any())).thenReturn(expectedScrapResponse); //then mockMvc.perform(delete("/scraps?event-id={eventId}", eventId) .header(HttpHeaders.AUTHORIZATION, "Bearer AccessToken")) .andExpect(status().isNoContent()) - .andDo(document("delete-scrap")); + .andDo(document("delete-scrap", SCRAPPED_EVENT_RESPONSE_FIELDS)); } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/scrap/api/ScrapApi.java b/backend/emm-sale/src/main/java/com/emmsale/scrap/api/ScrapApi.java index ce89d8fe2..51c697f3e 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/scrap/api/ScrapApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/scrap/api/ScrapApi.java @@ -33,14 +33,14 @@ public List findAllScraps(final Member member) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public void append(final Member member, @RequestBody final ScrapRequest scrapRequest) { - scrapCommandService.append(member, scrapRequest); + public EventResponse append(final Member member, @RequestBody final ScrapRequest scrapRequest) { + return scrapCommandService.append(member, scrapRequest); } @DeleteMapping @ResponseStatus(HttpStatus.NO_CONTENT) - public void delete(final Member member, @RequestParam("event-id") final Long eventId) { - scrapCommandService.deleteScrap(member, eventId); + public EventResponse delete(final Member member, @RequestParam("event-id") final Long eventId) { + return scrapCommandService.deleteScrap(member, eventId); } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/scrap/application/ScrapCommandService.java b/backend/emm-sale/src/main/java/com/emmsale/scrap/application/ScrapCommandService.java index 5e2bcccb6..5756e8ddb 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/scrap/application/ScrapCommandService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/scrap/application/ScrapCommandService.java @@ -1,9 +1,12 @@ package com.emmsale.scrap.application; +import com.emmsale.event.application.dto.EventResponse; import com.emmsale.event.domain.Event; import com.emmsale.event.domain.repository.EventRepository; import com.emmsale.event.exception.EventException; import com.emmsale.event.exception.EventExceptionType; +import com.emmsale.image.application.ImageQueryService; +import com.emmsale.image.domain.ImageType; import com.emmsale.member.domain.Member; import com.emmsale.scrap.application.dto.ScrapRequest; import com.emmsale.scrap.domain.Scrap; @@ -21,8 +24,10 @@ public class ScrapCommandService { private final ScrapRepository scrapRepository; private final EventRepository eventRepository; + private final ImageQueryService imageQueryService; - public void append(final Member member, final ScrapRequest scrapRequest) { + + public EventResponse append(final Member member, final ScrapRequest scrapRequest) { final Long memberId = member.getId(); final Long eventId = scrapRequest.getEventId(); @@ -32,10 +37,17 @@ public void append(final Member member, final ScrapRequest scrapRequest) { .orElseThrow(() -> new EventException(EventExceptionType.NOT_FOUND_EVENT)); scrapRepository.save(new Scrap(memberId, event)); + return EventResponse.from(event, + imageQueryService.findImagesOfContent(ImageType.EVENT, event.getId())); } - public void deleteScrap(final Member member, final Long eventId) { + public EventResponse deleteScrap(final Member member, final Long eventId) { + final Event event = eventRepository.findById(eventId) + .orElseThrow(() -> new EventException(EventExceptionType.NOT_FOUND_EVENT)); scrapRepository.deleteByMemberIdAndEventId(member.getId(), eventId); + return EventResponse.from(event, + imageQueryService.findImagesOfContent(ImageType.EVENT, eventId)); + } private void validateAlreadyScraped(final Long memberId, final Long eventId) { From 6ecb9f92dd1e472e2a1ce8edf59f62a9b8d3ec3f Mon Sep 17 00:00:00 2001 From: amaran-th Date: Sun, 5 Nov 2023 07:11:27 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=8B=9C=20=EC=8A=A4=ED=81=AC=EB=9E=A9?= =?UTF-8?q?=ED=95=9C=20=ED=96=89=EC=82=AC=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=A5=BC=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #823 --- .../src/documentTest/java/com/emmsale/ScrapApiTest.java | 1 - .../emm-sale/src/main/java/com/emmsale/scrap/api/ScrapApi.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java index c8ada91e4..e784bb06e 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java @@ -151,7 +151,6 @@ void findAllScraps() throws Exception { void append() throws Exception { //given final long eventId = 1L; - final ScrapRequest request = new ScrapRequest(eventId); final EventResponse expectedScrapResponse = new EventResponse( 1L, diff --git a/backend/emm-sale/src/main/java/com/emmsale/scrap/api/ScrapApi.java b/backend/emm-sale/src/main/java/com/emmsale/scrap/api/ScrapApi.java index 51c697f3e..7cc928110 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/scrap/api/ScrapApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/scrap/api/ScrapApi.java @@ -38,7 +38,7 @@ public EventResponse append(final Member member, @RequestBody final ScrapRequest } @DeleteMapping - @ResponseStatus(HttpStatus.NO_CONTENT) + @ResponseStatus(HttpStatus.OK) public EventResponse delete(final Member member, @RequestParam("event-id") final Long eventId) { return scrapCommandService.deleteScrap(member, eventId); } From cdf1f0f6bce9027ea7e9586c2b4b80f2e7358fb8 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Sun, 5 Nov 2023 07:12:09 +0900 Subject: [PATCH 3/7] =?UTF-8?q?docs:=20scrap=20=EA=B4=80=EB=A0=A8=20api=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20http=20=ED=8C=8C=EC=9D=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #823 --- .../src/main/resources/http/scrap.http | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 backend/emm-sale/src/main/resources/http/scrap.http diff --git a/backend/emm-sale/src/main/resources/http/scrap.http b/backend/emm-sale/src/main/resources/http/scrap.http new file mode 100644 index 000000000..d509767b3 --- /dev/null +++ b/backend/emm-sale/src/main/resources/http/scrap.http @@ -0,0 +1,21 @@ +### 스크랩 조회 + +GET http://localhost:8080/scraps +Content-Type: application/json +Authorization: bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaWF0IjoxNjk5MTI5NDAwLCJleHAiOjE3MDI3Mjk0MDB9.Gokmyr--11BIQCXHYv8_M156ngoZ6cIs9Exk7EEbwd0 + +### 스크랩 추가 + +POST http://localhost:8080/scraps +Content-Type: application/json +Authorization: bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaWF0IjoxNjk5MTI5NDAwLCJleHAiOjE3MDI3Mjk0MDB9.Gokmyr--11BIQCXHYv8_M156ngoZ6cIs9Exk7EEbwd0 + +{ + "eventId": 1 +} + +### 스크랩 삭제 + +DELETE http://localhost:8080/scraps?event-id=1 +Content-Type: application/json +Authorization: bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaWF0IjoxNjk5MTI5NDAwLCJleHAiOjE3MDI3Mjk0MDB9.Gokmyr--11BIQCXHYv8_M156ngoZ6cIs9Exk7EEbwd0 From 009adecaf1b1ef43fb1db5962997741b61e671ea Mon Sep 17 00:00:00 2001 From: amaran-th Date: Sun, 5 Nov 2023 17:42:53 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=20Message=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?api=20=EB=B0=98=ED=99=98=20=EB=AA=85=EC=84=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Message가 id와 sender(MemberReferenceResponse)를 추가로 반환하도록 수정 - Room이 Message와 interlocutor(MemberReferenceResponse)를 추가로 반환하도록 수정 #821 --- .../java/com/emmsale/RoomApiTest.java | 97 +++++++++++++------ .../MessageNotificationEvent.java | 2 +- .../application/MessageCommandService.java | 2 +- .../application/RoomQueryService.java | 6 +- .../application/dto/MessageResponse.java | 7 +- .../application/dto/RoomResponse.java | 25 +++-- .../emmsale/message_room/domain/Message.java | 23 ++++- .../persistence/MessageDao.java | 3 +- .../persistence/dto/MessageOverview.java | 1 + .../event_publisher/EventPublisherTest.java | 5 +- .../MessageCommandServiceTest.java | 9 +- .../application/RoomQueryServiceTest.java | 45 +++++---- .../domain/MessageRepositoryTest.java | 8 +- .../persistence/MessageDaoTest.java | 13 +-- 14 files changed, 156 insertions(+), 90 deletions(-) diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/RoomApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/RoomApiTest.java index 5ddc36255..3036b2a58 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/RoomApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/RoomApiTest.java @@ -13,9 +13,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.emmsale.member.application.dto.MemberReferenceResponse; +import com.emmsale.member.domain.Member; import com.emmsale.message_room.api.RoomApi; import com.emmsale.message_room.application.dto.MessageResponse; import com.emmsale.message_room.application.dto.RoomResponse; +import com.emmsale.message_room.domain.Message; import java.time.LocalDateTime; import java.util.List; import java.util.UUID; @@ -23,6 +26,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.http.HttpHeaders; +import org.springframework.restdocs.payload.JsonFieldType; import org.springframework.restdocs.payload.ResponseFieldsSnippet; import org.springframework.restdocs.request.PathParametersSnippet; import org.springframework.restdocs.request.RequestParametersSnippet; @@ -30,7 +34,17 @@ @WebMvcTest(RoomApi.class) class RoomApiTest extends MockMvcTestHelper { - private String accessToken = "Bearer AccessToken"; + private static final ResponseFieldsSnippet MESSAGES_RESPONSE_FIELDS = responseFields( + fieldWithPath("[].id").description("메시지의 ID"), + fieldWithPath("[].sender.id").description("메시지를 보낸 사람 ID"), + fieldWithPath("[].sender.name").description("메시지를 보낸 사람의 이름"), + fieldWithPath("[].sender.description").description("메시지를 보낸 사람의 한 줄 자기소개"), + fieldWithPath("[].sender.imageUrl").description("메시지를 보낸 사람의 프로필 이미지 URL"), + fieldWithPath("[].sender.githubUrl").description("메시지를 보낸 사람의 Github ID"), + fieldWithPath("[].content").description("메시지 내용"), + fieldWithPath("[].createdAt").description("메시지 보낸 시간") + ); + private static final String accessToken = "Bearer AccessToken"; @Test @DisplayName("findAllRoom() : 사용자의 쪽지함을 성공적으로 조회하면 200 OK를 반환할 수 있다.") @@ -42,20 +56,47 @@ void test_findAllRoom() throws Exception { final ResponseFieldsSnippet responseFields = responseFields( fieldWithPath("[].roomId").description("Room Id(String 타입의 UUID입니다)"), - fieldWithPath("[].interlocutorId").description("쪽지를 주고받는 상대방 ID"), - fieldWithPath("[].interlocutorName").description("쪽지를 주고받는 상대방의 이름"), - fieldWithPath("[].interlocutorProfile").description("쪽지를 주고받는 상대방 이미지 URL"), - fieldWithPath("[].recentlyMessage").description("최근 메시지 내용"), - fieldWithPath("[].recentlyMessageTime").description("최근 메시지 시간") + fieldWithPath("[].interlocutor.id").type(JsonFieldType.NUMBER) + .description("메세지를 주고받는 member의 식별자"), + fieldWithPath("[].interlocutor.name").type(JsonFieldType.STRING) + .description("메세지를 주고받는 member의 이름"), + fieldWithPath("[].interlocutor.description").type(JsonFieldType.STRING) + .description("메세지를 주고받는 member의 한줄 자기소개"), + fieldWithPath("[].interlocutor.imageUrl").type(JsonFieldType.STRING) + .description("메세지를 주고받는 member의 이미지 url"), + fieldWithPath("[].interlocutor.githubUrl").type(JsonFieldType.STRING) + .description("메세지를 주고받는 member의 github Url"), + fieldWithPath("[].recentlyMessage.id").description("최근 메시지 내용"), + fieldWithPath("[].recentlyMessage.content").description("최근 메시지 내용"), + fieldWithPath("[].recentlyMessage.sender.id").type(JsonFieldType.NUMBER) + .description("최근 메세지를 전송한 member의 식별자"), + fieldWithPath("[].recentlyMessage.sender.name").type(JsonFieldType.STRING) + .description("최근 메세지를 전송한 member의 이름"), + fieldWithPath("[].recentlyMessage.sender.description").type(JsonFieldType.STRING) + .description("최근 메세지를 전송한 member의 한줄 자기소개"), + fieldWithPath("[].recentlyMessage.sender.imageUrl").type(JsonFieldType.STRING) + .description("최근 메세지를 전송한 member의 이미지 url"), + fieldWithPath("[].recentlyMessage.sender.githubUrl").type(JsonFieldType.STRING) + .description("최근 메세지를 전송한 member의 github Url"), + fieldWithPath("[].recentlyMessage.createdAt").description("최근 메시지 시간") ); + final Member member1 = new Member(1L, 3L, "https://github.image", "receiver1", "amaran-th"); + final Member member2 = new Member(2L, 4L, "https://github.image2", "receiver2", "amaran-th2"); + final Member member3 = new Member(3L, 8L, "https://github.image2", "receiver3", "amaran-th3"); + final Message message1 = new Message(1L, "최근 메시지1", member1, "ROOMID1111", LocalDateTime.now()); + final Message message2 = new Message(2L, "최근 메시지2", member2, "ROOMID2222", + LocalDateTime.now().minusDays(2)); + final Message message3 = new Message(3L, "최근 메시지3", member3, "ROOMID3333", + LocalDateTime.now().minusDays(3)); + final List roomResponses = List.of( - new RoomResponse(UUID.randomUUID().toString(), 1L, "receiver1", "imageUrl1", "최근 메시지1", - LocalDateTime.now()), - new RoomResponse(UUID.randomUUID().toString(), 2L, "receiver2", "imageUrl2", "최근 메시지2", - LocalDateTime.now().minusDays(2)), - new RoomResponse(UUID.randomUUID().toString(), 1L, "receiver3", "imageUrl3", "최근 메시지3", - LocalDateTime.now().minusDays(3)) + new RoomResponse(UUID.randomUUID().toString(), MemberReferenceResponse.from(member1), + MessageResponse.from(message1)), + new RoomResponse(UUID.randomUUID().toString(), MemberReferenceResponse.from(member2), + MessageResponse.from(message2)), + new RoomResponse(UUID.randomUUID().toString(), MemberReferenceResponse.from(member3), + MessageResponse.from(message3)) ); when(roomQueryService.findAll(any(), anyLong())) @@ -78,20 +119,15 @@ void test_findByRoomId() throws Exception { parameterWithName("member-id").description("로그인 한 사용자 ID") ); - final ResponseFieldsSnippet responseFields = responseFields( - fieldWithPath("[].senderId").description("메시지를 보낸 사람 ID"), - fieldWithPath("[].content").description("메시지 내용"), - fieldWithPath("[].createdAt").description("메시지 보낸 시간") - ); - final PathParametersSnippet pathParams = pathParameters( parameterWithName("room-id").description("조회할 Room UUID") ); - + final Member member1 = new Member(1L, 3L, "https://github.image", "sender", "amaran-th"); + final Member member2 = new Member(2L, 4L, "https://github.image", "receiver", "amaran-th"); final List messageResponses = List.of( - new MessageResponse(1L, "내용1", LocalDateTime.now()), - new MessageResponse(2L, "내용2", LocalDateTime.now()), - new MessageResponse(1L, "내용3", LocalDateTime.now()) + new MessageResponse(1L, MemberReferenceResponse.from(member1), "내용1", LocalDateTime.now()), + new MessageResponse(2L, MemberReferenceResponse.from(member2), "내용2", LocalDateTime.now()), + new MessageResponse(3L, MemberReferenceResponse.from(member1), "내용3", LocalDateTime.now()) ); when(roomQueryService.findByRoomId(any(), any(), anyLong())) @@ -103,7 +139,7 @@ void test_findByRoomId() throws Exception { .header(HttpHeaders.AUTHORIZATION, accessToken)) .andExpect(status().isOk()) .andDo(print()) - .andDo(document("get-rooms-roomId", requestParam, responseFields, pathParams)); + .andDo(document("get-rooms-roomId", requestParam, MESSAGES_RESPONSE_FIELDS, pathParams)); } @Test @@ -115,16 +151,13 @@ void test_findByInterlocutorIds() throws Exception { parameterWithName("receiver-id").description("쪽지방 참여 상대방 ID") ); - final ResponseFieldsSnippet responseFields = responseFields( - fieldWithPath("[].senderId").description("메시지를 보낸 사람 ID"), - fieldWithPath("[].content").description("메시지 내용"), - fieldWithPath("[].createdAt").description("메시지 보낸 시간") - ); + final Member member1 = new Member(1L, 3L, "https://github.image", "sender", "amaran-th"); + final Member member2 = new Member(2L, 4L, "https://github.image", "receiver", "amaran-th"); final List messageResponses = List.of( - new MessageResponse(1L, "내용1", LocalDateTime.now()), - new MessageResponse(2L, "내용2", LocalDateTime.now()), - new MessageResponse(1L, "내용3", LocalDateTime.now()) + new MessageResponse(1L, MemberReferenceResponse.from(member1), "내용1", LocalDateTime.now()), + new MessageResponse(2L, MemberReferenceResponse.from(member2), "내용2", LocalDateTime.now()), + new MessageResponse(3L, MemberReferenceResponse.from(member1), "내용3", LocalDateTime.now()) ); when(roomQueryService.findByInterlocutorIds(anyLong(), anyLong(), any())) @@ -137,6 +170,6 @@ void test_findByInterlocutorIds() throws Exception { .header(HttpHeaders.AUTHORIZATION, accessToken)) .andExpect(status().isOk()) .andDo(print()) - .andDo(document("get-rooms-interlocutorId", requestParam, responseFields)); + .andDo(document("get-rooms-interlocutorId", requestParam, MESSAGES_RESPONSE_FIELDS)); } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/event_publisher/MessageNotificationEvent.java b/backend/emm-sale/src/main/java/com/emmsale/event_publisher/MessageNotificationEvent.java index 47b16ead6..235b6de6b 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event_publisher/MessageNotificationEvent.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event_publisher/MessageNotificationEvent.java @@ -19,7 +19,7 @@ public static MessageNotificationEvent of(final Message message, final Long rece return new MessageNotificationEvent( message.getRoomId(), message.getContent(), - message.getSenderId(), + message.getSender().getId(), receiverId, message.getCreatedAt() ); diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/MessageCommandService.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/MessageCommandService.java index e379d989c..bb5a92323 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/MessageCommandService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/MessageCommandService.java @@ -39,7 +39,7 @@ public MessageSendResponse sendMessage(final MessageSendRequest request, final M .map(room -> room.getRoomId().getUuid()) .orElseGet(() -> saveRooms(request)); - final Message message = new Message(request.getContent(), request.getSenderId(), + final Message message = new Message(request.getContent(), member, roomId, LocalDateTime.now()); messageRepository.save(message); diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java index e415ee31f..04be29708 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java @@ -38,7 +38,8 @@ public List findAll(final Member loginMember, final Long memberId) final Long loginMemberId = loginMember.getId(); - final List messageOverviews = messageDao.findRecentlyMessages(loginMemberId); + final List messageOverviews = messageDao.findRecentlyMessages( + loginMemberId); final Map interlocutorIdPerRoomExceptMe = groupingInterlocutorIdByRoom( messageOverviews, @@ -49,6 +50,9 @@ public List findAll(final Member loginMember, final Long memberId) .map(messageOverview -> RoomResponse.from( messageOverview, + memberRepository.findById(messageOverview.getSenderId()) + .orElseThrow(() -> new MemberException(NOT_FOUND_MEMBER)), + // TODO: 2023/11/05 N+1 문제 findInterlocutor(interlocutorIdPerRoomExceptMe.get(messageOverview.getRoomUUID())) )) .collect(Collectors.toList()); diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/MessageResponse.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/MessageResponse.java index 8faac4fbf..f3b44e4b0 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/MessageResponse.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/MessageResponse.java @@ -1,5 +1,6 @@ package com.emmsale.message_room.application.dto; +import com.emmsale.member.application.dto.MemberReferenceResponse; import com.emmsale.message_room.domain.Message; import com.fasterxml.jackson.annotation.JsonFormat; import java.time.LocalDateTime; @@ -10,14 +11,16 @@ @Getter public class MessageResponse { - private final Long senderId; + private final Long id; + private final MemberReferenceResponse sender; private final String content; @JsonFormat(pattern = "yyyy:MM:dd:HH:mm:ss") private final LocalDateTime createdAt; public static MessageResponse from(final Message message) { return new MessageResponse( - message.getSenderId(), + message.getId(), + MemberReferenceResponse.from(message.getSender()), message.getContent(), message.getCreatedAt() ); diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/RoomResponse.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/RoomResponse.java index 34f70a1a2..22cd71023 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/RoomResponse.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/RoomResponse.java @@ -1,9 +1,9 @@ package com.emmsale.message_room.application.dto; +import com.emmsale.member.application.dto.MemberReferenceResponse; import com.emmsale.member.domain.Member; +import com.emmsale.message_room.domain.Message; import com.emmsale.message_room.infrastructure.persistence.dto.MessageOverview; -import com.fasterxml.jackson.annotation.JsonFormat; -import java.time.LocalDateTime; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -12,24 +12,23 @@ public class RoomResponse { private final String roomId; - private final Long interlocutorId; - private final String interlocutorName; - private final String interlocutorProfile; - private final String recentlyMessage; - @JsonFormat(pattern = "yyyy:MM:dd:HH:mm:ss") - private final LocalDateTime recentlyMessageTime; + private final MemberReferenceResponse interlocutor; + private final MessageResponse recentlyMessage; public static RoomResponse from( final MessageOverview messageOverview, + final Member recentMessageSender, final Member interlocutor ) { return new RoomResponse( messageOverview.getRoomUUID(), - interlocutor.getId(), - interlocutor.getName(), - interlocutor.getImageUrl(), - messageOverview.getContent(), - messageOverview.getCreatedAt() + MemberReferenceResponse.from(interlocutor), + MessageResponse.from(new Message( + messageOverview.getId(), + messageOverview.getContent(), + recentMessageSender, + messageOverview.getRoomUUID(), + messageOverview.getCreatedAt())) ); } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/Message.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/Message.java index 2c72f890a..329809bf1 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/Message.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/Message.java @@ -1,11 +1,14 @@ package com.emmsale.message_room.domain; +import com.emmsale.member.domain.Member; import java.time.LocalDateTime; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -22,8 +25,9 @@ public class Message { @Column(nullable = false) private String content; - @Column(nullable = false) - private Long senderId; + @ManyToOne + @JoinColumn(nullable = false) + private Member sender; @Column(nullable = false) private String roomId; @@ -31,14 +35,25 @@ public class Message { private LocalDateTime createdAt; public Message( + final Long id, final String content, - final Long senderId, + final Member sender, final String roomId, final LocalDateTime createdAt ) { + this.id = id; this.content = content; - this.senderId = senderId; + this.sender = sender; this.roomId = roomId; this.createdAt = createdAt; } + + public Message( + final String content, + final Member sender, + final String roomId, + final LocalDateTime createdAt + ) { + this(null, content, sender, roomId, createdAt); + } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/MessageDao.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/MessageDao.java index 521157ef2..7627785a5 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/MessageDao.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/MessageDao.java @@ -16,6 +16,7 @@ public class MessageDao { new MessageOverview( rs.getLong("id"), rs.getString("content"), + rs.getLong("sender_id"), rs.getTimestamp("created_at").toLocalDateTime(), rs.getString("room_id") ); @@ -26,7 +27,7 @@ public List findRecentlyMessages(final Long memberId) { StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder - .append("SELECT m2.id, m2.content, m2.created_at, m2.room_id ") + .append("SELECT m2.id, m2.content, m2.sender_id, m2.created_at, m2.room_id ") .append("FROM room r ") .append("JOIN (SELECT room_id, MAX(created_at) as max_created_at ") .append(" FROM message ") diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/dto/MessageOverview.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/dto/MessageOverview.java index a4e86966a..f31bc0fd8 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/dto/MessageOverview.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/dto/MessageOverview.java @@ -10,6 +10,7 @@ public class MessageOverview { private final Long id; private final String content; + private final Long senderId; private final LocalDateTime createdAt; private final String roomUUID; } diff --git a/backend/emm-sale/src/test/java/com/emmsale/event_publisher/EventPublisherTest.java b/backend/emm-sale/src/test/java/com/emmsale/event_publisher/EventPublisherTest.java index 5cb32927c..f622e7158 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event_publisher/EventPublisherTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event_publisher/EventPublisherTest.java @@ -312,7 +312,8 @@ void test_publish_comment_not_notification_deletedComment2() throws Exception { @DisplayName("publish() : message를 받아서, Event로 변환 후 publish한다.") void publishMessageEvent() { //given - final Message message = new Message("content", 1L, "roomId", LocalDateTime.now()); + final Member sender = memberRepository.findById(1L).get(); + final Message message = new Message("content", sender, "roomId", LocalDateTime.now()); final Long receiverId = 2L; //when @@ -328,7 +329,7 @@ void publishMessageEvent() { final MessageNotificationEvent expectedEvent = new MessageNotificationEvent( message.getRoomId(), message.getContent(), - message.getSenderId(), + message.getSender().getId(), receiverId, message.getCreatedAt() ); diff --git a/backend/emm-sale/src/test/java/com/emmsale/message_room/application/MessageCommandServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/message_room/application/MessageCommandServiceTest.java index fac690350..9a89d68d3 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/message_room/application/MessageCommandServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/message_room/application/MessageCommandServiceTest.java @@ -60,14 +60,15 @@ void alreadyRoomExist() { )); final MessageSendRequest request = new MessageSendRequest(requesterId, receiverId, content); - final Message expected = new Message(content, requesterId, roomUUID, LocalDateTime.now()); + final Message expected = new Message(content, member, roomUUID, LocalDateTime.now()); //when messageCommandService.sendMessage(request, member); //then assertThat(messageRepository.findAll()) - .usingRecursiveFieldByFieldElementComparatorIgnoringFields("id", "createdAt") + .usingRecursiveFieldByFieldElementComparatorIgnoringFields("id", "createdAt", + "sender.createdAt", "sender.updatedAt") .containsExactlyInAnyOrder(expected); } @@ -81,7 +82,7 @@ void notExistRoom() { final String content = "메시지 내용"; final MessageSendRequest request = new MessageSendRequest(requesterId, receiverId, content); - final Message expected = new Message(content, requesterId, null, LocalDateTime.now()); + final Message expected = new Message(content, member, null, LocalDateTime.now()); //when messageCommandService.sendMessage(request, member); @@ -90,7 +91,7 @@ void notExistRoom() { assertAll( () -> assertThat(messageRepository.findAll()) .usingRecursiveFieldByFieldElementComparatorIgnoringFields("id", "createdAt", - "roomId") + "roomId", "sender.createdAt", "sender.updatedAt") .containsExactly(expected), () -> verify(firebaseCloudMessageClient, times(1)) .sendMessageTo(any(MessageNotificationEvent.class)) diff --git a/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java index 3de1b97be..aaa5c6719 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java @@ -4,6 +4,7 @@ import com.emmsale.helper.ServiceIntegrationTestHelper; import com.emmsale.member.MemberFixture; +import com.emmsale.member.application.dto.MemberReferenceResponse; import com.emmsale.member.domain.Member; import com.emmsale.member.domain.MemberRepository; import com.emmsale.message_room.application.dto.MessageResponse; @@ -79,26 +80,26 @@ void test_findAll() throws Exception { //given final Message resultMessage1 = new Message( "방1메시지3", - loginMember.getId(), + loginMember, room1UUID, LocalDateTime.parse("2023-10-07T16:45:39") ); final Message resultMessage2 = new Message( "방2메시지4", - room2Interlocutor.getId(), + room2Interlocutor, room2UUID, LocalDateTime.parse("2023-10-07T16:45:39") ); messageRepository.saveAll( List.of( - new Message("방1메시지1", loginMember.getId(), room1UUID, + new Message("방1메시지1", loginMember, room1UUID, LocalDateTime.parse("2023-05-07T16:45:39")), - new Message("방1메시지2", loginMember.getId(), room1UUID, + new Message("방1메시지2", loginMember, room1UUID, LocalDateTime.parse("2023-06-07T16:45:39")), resultMessage1, resultMessage2, - new Message("방3메시지5", loginMember.getId(), room3UUID, + new Message("방3메시지5", loginMember, room3UUID, LocalDateTime.parse("2023-08-07T16:45:39")) ) ); @@ -106,6 +107,7 @@ void test_findAll() throws Exception { final MessageOverview messageOverview1 = new MessageOverview( resultMessage1.getId(), resultMessage1.getContent(), + resultMessage1.getSender().getId(), resultMessage1.getCreatedAt(), resultMessage1.getRoomId() ); @@ -113,14 +115,15 @@ void test_findAll() throws Exception { final MessageOverview messageOverview2 = new MessageOverview( resultMessage2.getId(), resultMessage2.getContent(), + resultMessage2.getSender().getId(), resultMessage2.getCreatedAt(), resultMessage2.getRoomId() ); final List expect = List.of( - RoomResponse.from(messageOverview1, + RoomResponse.from(messageOverview1, resultMessage1.getSender(), memberRepository.findById(room1Interlocutor.getId()).get()), - RoomResponse.from(messageOverview2, + RoomResponse.from(messageOverview2, resultMessage2.getSender(), memberRepository.findById(room2Interlocutor.getId()).get()) ); @@ -137,26 +140,28 @@ void test_findAll() throws Exception { @DisplayName("findByRoomId() : Room UUID를 통해 Room에 있는 메시지들을 조회할 수 있다.") void test_findByRoomId() throws Exception { //given - final Message room1Message1 = new Message("방1메시지1", loginMember.getId(), room1UUID, + final Message room1Message1 = new Message("방1메시지1", loginMember, room1UUID, LocalDateTime.parse("2023-05-07T16:45:39")); - final Message room1Message2 = new Message("방1메시지2", loginMember.getId(), room1UUID, + final Message room1Message2 = new Message("방1메시지2", loginMember, room1UUID, LocalDateTime.parse("2023-06-07T16:45:38")); messageRepository.saveAll( List.of( room1Message1, room1Message2, - new Message("방2메시지3", loginMember.getId(), room2UUID, + new Message("방2메시지3", loginMember, room2UUID, LocalDateTime.parse("2023-10-07T16:45:39")), - new Message("방2메시지4", room1Interlocutor.getId(), room2UUID, + new Message("방2메시지4", room1Interlocutor, room2UUID, LocalDateTime.parse("2023-10-07T16:45:39")) ) ); final List expect = List.of( - new MessageResponse(room1Message1.getSenderId(), room1Message1.getContent(), + new MessageResponse(room1Message1.getId(), + MemberReferenceResponse.from(room1Message1.getSender()), room1Message1.getContent(), room1Message1.getCreatedAt()), - new MessageResponse(room1Message2.getSenderId(), room1Message2.getContent(), + new MessageResponse(room1Message2.getId(), + MemberReferenceResponse.from(room1Message2.getSender()), room1Message2.getContent(), room1Message2.getCreatedAt()) ); @@ -174,26 +179,28 @@ void test_findByRoomId() throws Exception { @DisplayName("findByInterlocutorIds() : Room 에 참여한 사용자의 ID를 통해 쪽지방을 조회할 수 있다.") void test_findByInterlocutorIds() throws Exception { //given - final Message room1Message1 = new Message("방1메시지1", loginMember.getId(), room1UUID, + final Message room1Message1 = new Message("방1메시지1", loginMember, room1UUID, LocalDateTime.parse("2023-05-07T16:45:39")); - final Message room1Message2 = new Message("방1메시지2", loginMember.getId(), room1UUID, + final Message room1Message2 = new Message("방1메시지2", loginMember, room1UUID, LocalDateTime.parse("2023-06-07T16:45:38")); messageRepository.saveAll( List.of( room1Message1, room1Message2, - new Message("방2메시지3", loginMember.getId(), room2UUID, + new Message("방2메시지3", loginMember, room2UUID, LocalDateTime.parse("2023-10-07T16:45:39")), - new Message("방2메시지4", room1Interlocutor.getId(), room2UUID, + new Message("방2메시지4", room1Interlocutor, room2UUID, LocalDateTime.parse("2023-10-07T16:45:39")) ) ); final List expect = List.of( - new MessageResponse(room1Message1.getSenderId(), room1Message1.getContent(), + new MessageResponse(room1Message1.getId(), + MemberReferenceResponse.from(room1Message1.getSender()), room1Message1.getContent(), room1Message1.getCreatedAt()), - new MessageResponse(room1Message2.getSenderId(), room1Message2.getContent(), + new MessageResponse(room1Message2.getId(), + MemberReferenceResponse.from(room1Message2.getSender()), room1Message2.getContent(), room1Message2.getCreatedAt()) ); diff --git a/backend/emm-sale/src/test/java/com/emmsale/message_room/domain/MessageRepositoryTest.java b/backend/emm-sale/src/test/java/com/emmsale/message_room/domain/MessageRepositoryTest.java index b5ef58669..cfcf34ac8 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/message_room/domain/MessageRepositoryTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/message_room/domain/MessageRepositoryTest.java @@ -38,18 +38,18 @@ void test_findByRoomId() throws Exception { final Room member3Room2 = new Room(new RoomId(room2UUID, room2Interlocutor.getId()), LocalDateTime.parse("2023-09-07T16:48:24")); - final Message room1Message1 = new Message("방1메시지1", loginMember.getId(), room1UUID, + final Message room1Message1 = new Message("방1메시지1", loginMember, room1UUID, LocalDateTime.parse("2023-05-07T16:45:39")); - final Message room1Message2 = new Message("방1메시지2", loginMember.getId(), room1UUID, + final Message room1Message2 = new Message("방1메시지2", loginMember, room1UUID, LocalDateTime.parse("2023-06-07T16:45:38")); messageRepository.saveAll( List.of( room1Message1, room1Message2, - new Message("방2메시지3", loginMember.getId(), room2UUID, + new Message("방2메시지3", loginMember, room2UUID, LocalDateTime.parse("2023-10-07T16:45:39")), - new Message("방2메시지4", room1Interlocutor.getId(), room2UUID, + new Message("방2메시지4", room1Interlocutor, room2UUID, LocalDateTime.parse("2023-10-07T16:45:39")) ) ); diff --git a/backend/emm-sale/src/test/java/com/emmsale/message_room/infrastructure/persistence/MessageDaoTest.java b/backend/emm-sale/src/test/java/com/emmsale/message_room/infrastructure/persistence/MessageDaoTest.java index d418c309e..3aa1f63ff 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/message_room/infrastructure/persistence/MessageDaoTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/message_room/infrastructure/persistence/MessageDaoTest.java @@ -18,7 +18,6 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.annotation.Rollback; class MessageDaoTest extends JpaRepositorySliceTestHelper { @@ -82,26 +81,26 @@ void test_findRecentlyMessages() throws Exception { final Message resultMessage1 = new Message( "방1메시지3", - loginMember.getId(), + loginMember, room1UUID, LocalDateTime.parse("2023-10-07T16:45:39") ); final Message resultMessage2 = new Message( "방2메시지4", - room2Interlocutor.getId(), + room2Interlocutor, room2UUID, LocalDateTime.parse("2023-10-07T16:45:39") ); messageRepository.saveAll( List.of( - new Message("방1메시지1", loginMember.getId(), room1UUID, + new Message("방1메시지1", loginMember, room1UUID, LocalDateTime.parse("2023-05-07T16:45:39")), - new Message("방1메시지2", loginMember.getId(), room1UUID, + new Message("방1메시지2", loginMember, room1UUID, LocalDateTime.parse("2023-06-07T16:45:39")), resultMessage1, resultMessage2, - new Message("방3메시지5", loginMember.getId(), room3UUID, + new Message("방3메시지5", loginMember, room3UUID, LocalDateTime.parse("2023-08-07T16:45:39")) ) ); @@ -110,12 +109,14 @@ void test_findRecentlyMessages() throws Exception { new MessageOverview( resultMessage1.getId(), resultMessage1.getContent(), + resultMessage1.getSender().getId(), resultMessage1.getCreatedAt(), resultMessage1.getRoomId() ), new MessageOverview( resultMessage2.getId(), resultMessage2.getContent(), + resultMessage2.getSender().getId(), resultMessage2.getCreatedAt(), resultMessage2.getRoomId() ) From 18e88667ba1c6936389abe0e704fd904e83314f0 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Sun, 5 Nov 2023 18:02:23 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=20Message=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?api=20=EB=B0=98=ED=99=98=20=EB=AA=85=EC=84=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 쪽지방 조회 시 조회하려는 회원의 id를 입력받지 않도록 수정 #821 --- .../java/com/emmsale/RoomApiTest.java | 12 +++--------- .../com/emmsale/message_room/api/RoomApi.java | 8 +++----- .../application/RoomQueryService.java | 17 ++++++++++------- .../message_room/domain/MessageRepository.java | 1 + .../message_room/domain/RoomRepository.java | 2 ++ .../application/RoomQueryServiceTest.java | 4 +--- 6 files changed, 20 insertions(+), 24 deletions(-) diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/RoomApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/RoomApiTest.java index 3036b2a58..c99dfe7c1 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/RoomApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/RoomApiTest.java @@ -115,9 +115,6 @@ void test_findAllRoom() throws Exception { @DisplayName("findByRoomId() : Room Id로 쪽지방을 성공적으로 조회하면 200 OK를 반환할 수 있다.") void test_findByRoomId() throws Exception { //given - final RequestParametersSnippet requestParam = requestParameters( - parameterWithName("member-id").description("로그인 한 사용자 ID") - ); final PathParametersSnippet pathParams = pathParameters( parameterWithName("room-id").description("조회할 Room UUID") @@ -130,16 +127,15 @@ void test_findByRoomId() throws Exception { new MessageResponse(3L, MemberReferenceResponse.from(member1), "내용3", LocalDateTime.now()) ); - when(roomQueryService.findByRoomId(any(), any(), anyLong())) + when(roomQueryService.findByRoomId(any(), any())) .thenReturn(messageResponses); //when & then mockMvc.perform(get("/rooms/{room-id}", 1L) - .queryParam("member-id", "1") .header(HttpHeaders.AUTHORIZATION, accessToken)) .andExpect(status().isOk()) .andDo(print()) - .andDo(document("get-rooms-roomId", requestParam, MESSAGES_RESPONSE_FIELDS, pathParams)); + .andDo(document("get-rooms-roomId", MESSAGES_RESPONSE_FIELDS, pathParams)); } @Test @@ -147,7 +143,6 @@ void test_findByRoomId() throws Exception { void test_findByInterlocutorIds() throws Exception { //given final RequestParametersSnippet requestParam = requestParameters( - parameterWithName("member-id").description("로그인 한 사용자 ID"), parameterWithName("receiver-id").description("쪽지방 참여 상대방 ID") ); @@ -160,12 +155,11 @@ void test_findByInterlocutorIds() throws Exception { new MessageResponse(3L, MemberReferenceResponse.from(member1), "내용3", LocalDateTime.now()) ); - when(roomQueryService.findByInterlocutorIds(anyLong(), anyLong(), any())) + when(roomQueryService.findByInterlocutorIds(anyLong(), any())) .thenReturn(messageResponses); //when & then mockMvc.perform(get("/rooms") - .queryParam("member-id", "1") .queryParam("receiver-id", "1") .header(HttpHeaders.AUTHORIZATION, accessToken)) .andExpect(status().isOk()) diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/api/RoomApi.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/api/RoomApi.java index 3e55d95bd..1695436f2 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/api/RoomApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/api/RoomApi.java @@ -28,18 +28,16 @@ public List findAllRoom( @GetMapping("/rooms/{room-id}") public List findByRoomId( final Member member, - @PathVariable("room-id") final String roomId, - @RequestParam("member-id") final Long memberId + @PathVariable("room-id") final String roomId ) { - return roomQueryService.findByRoomId(member, roomId, memberId); + return roomQueryService.findByRoomId(member, roomId); } @GetMapping("/rooms") public List findByInterlocutorIds( @RequestParam("receiver-id") final Long receiverId, - @RequestParam("member-id") final Long memberId, final Member loginMember ) { - return roomQueryService.findByInterlocutorIds(receiverId, memberId, loginMember); + return roomQueryService.findByInterlocutorIds(receiverId, loginMember); } } diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java index 04be29708..f690c55b3 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java @@ -11,6 +11,7 @@ import com.emmsale.message_room.application.dto.RoomResponse; import com.emmsale.message_room.domain.MessageRepository; import com.emmsale.message_room.domain.Room; +import com.emmsale.message_room.domain.RoomId; import com.emmsale.message_room.domain.RoomRepository; import com.emmsale.message_room.exception.MessageRoomException; import com.emmsale.message_room.infrastructure.persistence.MessageDao; @@ -88,14 +89,19 @@ private Member findInterlocutor(final Long interlocutorId) { public List findByRoomId( final Member loginMember, - final String roomId, - final Long memberId + final String roomId ) { - validateSameMember(loginMember, memberId); + validateAuthorizedMember(loginMember, roomId); return findMessageByRoomUUID(roomId); } + private void validateAuthorizedMember(final Member loginMember, final String roomId) { + if (!roomRepository.existsByRoomId(new RoomId(roomId, loginMember.getId()))) { + throw new MemberException(NOT_MATCHING_TOKEN_AND_LOGIN_MEMBER); + } + } + private List findMessageByRoomUUID(final String roomId) { return messageRepository.findByRoomUUID(roomId) .stream() @@ -106,12 +112,9 @@ private List findMessageByRoomUUID(final String roomId) { public List findByInterlocutorIds( final Long receiverId, - final Long senderId, final Member loginMember ) { - validateSameMember(loginMember, senderId); - - final Room room = roomRepository.findByInterlocutorIds(senderId, receiverId) + final Room room = roomRepository.findByInterlocutorIds(loginMember.getId(), receiverId) .orElseThrow(() -> new MessageRoomException(NOT_FOUND_MESSAGE_ROOM)); return findMessageByRoomUUID(room.getRoomId().getUuid()); diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/MessageRepository.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/MessageRepository.java index bb05762d7..c795433f3 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/MessageRepository.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/MessageRepository.java @@ -8,4 +8,5 @@ public interface MessageRepository extends JpaRepository { @Query("select m from Message m where m.roomId = :roomUUID") List findByRoomUUID(String roomUUID); + } diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/RoomRepository.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/RoomRepository.java index 667a6ac80..30f7cab02 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/RoomRepository.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/domain/RoomRepository.java @@ -19,4 +19,6 @@ Optional findByInterlocutorIds( @Param("member1") final Long interlocutorId1, @Param("member2") final Long interlocutorId2 ); + + boolean existsByRoomId(RoomId roomId); } diff --git a/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java index aaa5c6719..cd1ccb5af 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java @@ -166,8 +166,7 @@ void test_findByRoomId() throws Exception { ); //when - final List actual = roomQueryService.findByRoomId(loginMember, room1UUID, - loginMember.getId()); + final List actual = roomQueryService.findByRoomId(loginMember, room1UUID); //then Assertions.assertThat(actual) @@ -207,7 +206,6 @@ void test_findByInterlocutorIds() throws Exception { //when final List actual = roomQueryService.findByInterlocutorIds( room1Interlocutor.getId(), - loginMember.getId(), loginMember ); From 9998b29fa7f0d798240862a9be7fb1b5eba62593 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Sun, 5 Nov 2023 18:04:02 +0900 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=8B=9C=20=EA=B2=80=EC=A6=9D=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=83=81=ED=83=9C=EC=BD=94=EB=93=9C=EB=A5=BC=20noC?= =?UTF-8?q?ontent=20=EB=8C=80=EC=8B=A0=20ok=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #821 --- .../src/documentTest/java/com/emmsale/ScrapApiTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java index e784bb06e..9b7d2d5bb 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/ScrapApiTest.java @@ -214,7 +214,7 @@ void deleteScrap() throws Exception { //then mockMvc.perform(delete("/scraps?event-id={eventId}", eventId) .header(HttpHeaders.AUTHORIZATION, "Bearer AccessToken")) - .andExpect(status().isNoContent()) + .andExpect(status().isOk()) .andDo(document("delete-scrap", SCRAPPED_EVENT_RESPONSE_FIELDS)); } } From 0d180a6470ab477a92ba2611544aa45924a6ff41 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Wed, 8 Nov 2023 20:27:58 +0900 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20N+1=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #821 --- .../java/com/emmsale/member/domain/Member.java | 13 ++++++++----- .../application/RoomQueryService.java | 3 --- .../application/dto/RoomResponse.java | 3 +-- .../infrastructure/persistence/MessageDao.java | 17 ++++++++++++++--- .../persistence/dto/MessageOverview.java | 3 ++- .../application/RoomQueryServiceTest.java | 8 ++++---- .../persistence/MessageDaoTest.java | 5 +++-- 7 files changed, 32 insertions(+), 20 deletions(-) diff --git a/backend/emm-sale/src/main/java/com/emmsale/member/domain/Member.java b/backend/emm-sale/src/main/java/com/emmsale/member/domain/Member.java index 51003a9d1..4f916de76 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/member/domain/Member.java +++ b/backend/emm-sale/src/main/java/com/emmsale/member/domain/Member.java @@ -35,20 +35,23 @@ public class Member extends BaseEntity { private String githubUsername; public Member(final Long id, final Long githubId, final String imageUrl, final String name, + final String description, final String githubUsername) { this.id = id; this.githubId = githubId; this.imageUrl = imageUrl; this.name = name; - this.description = DEFAULT_DESCRIPTION; + this.description = description; this.githubUsername = githubUsername; } + public Member(final Long id, final Long githubId, final String imageUrl, final String name, + final String githubUsername) { + this(id, githubId, imageUrl, name, DEFAULT_DESCRIPTION, githubUsername); + } + public Member(final Long githubId, final String imageUrl, final String githubUsername) { - this.githubId = githubId; - this.imageUrl = imageUrl; - this.description = DEFAULT_DESCRIPTION; - this.githubUsername = githubUsername; + this(null, githubId, imageUrl, null, DEFAULT_DESCRIPTION, githubUsername); } public void updateName(final String name) { diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java index f690c55b3..93da4734d 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/RoomQueryService.java @@ -51,9 +51,6 @@ public List findAll(final Member loginMember, final Long memberId) .map(messageOverview -> RoomResponse.from( messageOverview, - memberRepository.findById(messageOverview.getSenderId()) - .orElseThrow(() -> new MemberException(NOT_FOUND_MEMBER)), - // TODO: 2023/11/05 N+1 문제 findInterlocutor(interlocutorIdPerRoomExceptMe.get(messageOverview.getRoomUUID())) )) .collect(Collectors.toList()); diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/RoomResponse.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/RoomResponse.java index 22cd71023..222fcd79b 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/RoomResponse.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/application/dto/RoomResponse.java @@ -17,7 +17,6 @@ public class RoomResponse { public static RoomResponse from( final MessageOverview messageOverview, - final Member recentMessageSender, final Member interlocutor ) { return new RoomResponse( @@ -26,7 +25,7 @@ public static RoomResponse from( MessageResponse.from(new Message( messageOverview.getId(), messageOverview.getContent(), - recentMessageSender, + messageOverview.getSender(), messageOverview.getRoomUUID(), messageOverview.getCreatedAt())) ); diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/MessageDao.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/MessageDao.java index 7627785a5..21f991a99 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/MessageDao.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/MessageDao.java @@ -1,6 +1,7 @@ package com.emmsale.message_room.infrastructure.persistence; +import com.emmsale.member.domain.Member; import com.emmsale.message_room.infrastructure.persistence.dto.MessageOverview; import java.util.List; import lombok.RequiredArgsConstructor; @@ -14,9 +15,16 @@ public class MessageDao { private static final RowMapper ROW_MAPPER = (rs, rowNum) -> new MessageOverview( - rs.getLong("id"), + rs.getLong("m2.id"), rs.getString("content"), - rs.getLong("sender_id"), + new Member( + rs.getLong("sender.id"), + rs.getLong("github_id"), + rs.getString("image_url"), + rs.getString("name"), + rs.getString("description"), + rs.getString("github_username") + ), rs.getTimestamp("created_at").toLocalDateTime(), rs.getString("room_id") ); @@ -27,12 +35,15 @@ public List findRecentlyMessages(final Long memberId) { StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder - .append("SELECT m2.id, m2.content, m2.sender_id, m2.created_at, m2.room_id ") + .append("SELECT m2.id, m2.content, m2.sender_id, m2.created_at, m2.room_id, ") + .append( + "sender.id, sender.github_id, sender.image_url, sender.name, sender.description, sender.github_username ") .append("FROM room r ") .append("JOIN (SELECT room_id, MAX(created_at) as max_created_at ") .append(" FROM message ") .append(" GROUP BY room_id) m1 ON r.uuid = m1.room_id ") .append("JOIN message m2 ON m1.room_id = m2.room_id AND m1.max_created_at = m2.created_at ") + .append("JOIN member sender ON m2.sender_id = sender.id ") .append("WHERE r.member_id = ? ") .append("AND m2.created_at > r.last_exited_time ") .append("ORDER BY m2.created_at DESC"); diff --git a/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/dto/MessageOverview.java b/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/dto/MessageOverview.java index f31bc0fd8..3bd09f8db 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/dto/MessageOverview.java +++ b/backend/emm-sale/src/main/java/com/emmsale/message_room/infrastructure/persistence/dto/MessageOverview.java @@ -1,5 +1,6 @@ package com.emmsale.message_room.infrastructure.persistence.dto; +import com.emmsale.member.domain.Member; import java.time.LocalDateTime; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -10,7 +11,7 @@ public class MessageOverview { private final Long id; private final String content; - private final Long senderId; + private final Member sender; private final LocalDateTime createdAt; private final String roomUUID; } diff --git a/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java index cd1ccb5af..7ecdbfeda 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/message_room/application/RoomQueryServiceTest.java @@ -107,7 +107,7 @@ void test_findAll() throws Exception { final MessageOverview messageOverview1 = new MessageOverview( resultMessage1.getId(), resultMessage1.getContent(), - resultMessage1.getSender().getId(), + resultMessage1.getSender(), resultMessage1.getCreatedAt(), resultMessage1.getRoomId() ); @@ -115,15 +115,15 @@ void test_findAll() throws Exception { final MessageOverview messageOverview2 = new MessageOverview( resultMessage2.getId(), resultMessage2.getContent(), - resultMessage2.getSender().getId(), + resultMessage2.getSender(), resultMessage2.getCreatedAt(), resultMessage2.getRoomId() ); final List expect = List.of( - RoomResponse.from(messageOverview1, resultMessage1.getSender(), + RoomResponse.from(messageOverview1, memberRepository.findById(room1Interlocutor.getId()).get()), - RoomResponse.from(messageOverview2, resultMessage2.getSender(), + RoomResponse.from(messageOverview2, memberRepository.findById(room2Interlocutor.getId()).get()) ); diff --git a/backend/emm-sale/src/test/java/com/emmsale/message_room/infrastructure/persistence/MessageDaoTest.java b/backend/emm-sale/src/test/java/com/emmsale/message_room/infrastructure/persistence/MessageDaoTest.java index 3aa1f63ff..c8ac8696d 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/message_room/infrastructure/persistence/MessageDaoTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/message_room/infrastructure/persistence/MessageDaoTest.java @@ -109,14 +109,14 @@ void test_findRecentlyMessages() throws Exception { new MessageOverview( resultMessage1.getId(), resultMessage1.getContent(), - resultMessage1.getSender().getId(), + resultMessage1.getSender(), resultMessage1.getCreatedAt(), resultMessage1.getRoomId() ), new MessageOverview( resultMessage2.getId(), resultMessage2.getContent(), - resultMessage2.getSender().getId(), + resultMessage2.getSender(), resultMessage2.getCreatedAt(), resultMessage2.getRoomId() ) @@ -128,6 +128,7 @@ void test_findRecentlyMessages() throws Exception { //then Assertions.assertThat(actual) .usingRecursiveComparison() + .ignoringFields("sender.createdAt", "sender.updatedAt") .isEqualTo(expect); } }