From 0f756aed625601f668e922218dd04b5216e4c637 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 26 Jan 2025 20:40:21 +0900 Subject: [PATCH 1/2] =?UTF-8?q?CLAP-145=20Feature:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=20=EC=9D=BD=EC=9D=8C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ManagementNotificationController.java | 8 ++++++++ .../persistense/NotificationPersistenceAdapter.java | 8 ++++++++ .../notification/NotificationRepository.java | 4 ++++ .../notification/UpdateNotificationUsecase.java | 2 ++ .../outbound/notification/LoadNotificationPort.java | 2 ++ .../notification/ReadNotificationService.java | 12 ++++++++++++ 6 files changed, 36 insertions(+) diff --git a/src/main/java/clap/server/adapter/inbound/web/notification/ManagementNotificationController.java b/src/main/java/clap/server/adapter/inbound/web/notification/ManagementNotificationController.java index d4d37dc1..7e41862c 100644 --- a/src/main/java/clap/server/adapter/inbound/web/notification/ManagementNotificationController.java +++ b/src/main/java/clap/server/adapter/inbound/web/notification/ManagementNotificationController.java @@ -1,5 +1,6 @@ package clap.server.adapter.inbound.web.notification; +import clap.server.adapter.inbound.security.SecurityUserDetails; import clap.server.application.port.inbound.notification.UpdateNotificationUsecase; import clap.server.common.annotation.architecture.WebAdapter; import io.swagger.v3.oas.annotations.Operation; @@ -7,6 +8,7 @@ import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -27,4 +29,10 @@ public class ManagementNotificationController { public void updateNotificationIsRead(@PathVariable Long notificationId) { updateNotificationUsecase.updateNotification(notificationId); } + + @Operation(summary = "알림 목록에서 전체 읽음 버튼을 눌렀을 때 전체 읽음 처리") + @PatchMapping + public void updateAllNotificationIsRead(@AuthenticationPrincipal SecurityUserDetails userInfo) { + updateNotificationUsecase.updateAllNotification(userInfo.getUserId()); + } } diff --git a/src/main/java/clap/server/adapter/outbound/persistense/NotificationPersistenceAdapter.java b/src/main/java/clap/server/adapter/outbound/persistense/NotificationPersistenceAdapter.java index 5e94aa6c..40e0f5de 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/NotificationPersistenceAdapter.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/NotificationPersistenceAdapter.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @PersistenceAdapter @RequiredArgsConstructor @@ -36,6 +37,13 @@ public Page findAllByReceiverId(Long receiverId, P return notificationList.map(NotificationMapper::toFindNoticeListResponse); } + @Override + public List findNotificationsByMemberId(Long memberId) { + return notificationRepository.findAllByReceiver_MemberId(memberId) + .stream().map(notificationPersistenceMapper::toDomain) + .collect(Collectors.toList()); + } + @Override public void save(Notification notification) { notificationRepository.save(notificationPersistenceMapper.toEntity(notification)); diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/notification/NotificationRepository.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/notification/NotificationRepository.java index 68e99315..37aebd57 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/notification/NotificationRepository.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/notification/NotificationRepository.java @@ -6,9 +6,13 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface NotificationRepository extends JpaRepository { Page findAllByReceiver_MemberId(Long receiverId, Pageable pageable); + + List findAllByReceiver_MemberId(Long memberId); } \ No newline at end of file diff --git a/src/main/java/clap/server/application/port/inbound/notification/UpdateNotificationUsecase.java b/src/main/java/clap/server/application/port/inbound/notification/UpdateNotificationUsecase.java index 91c124fe..858b2cb4 100644 --- a/src/main/java/clap/server/application/port/inbound/notification/UpdateNotificationUsecase.java +++ b/src/main/java/clap/server/application/port/inbound/notification/UpdateNotificationUsecase.java @@ -2,4 +2,6 @@ public interface UpdateNotificationUsecase { void updateNotification(Long notificationId); + + void updateAllNotification(Long memberId); } diff --git a/src/main/java/clap/server/application/port/outbound/notification/LoadNotificationPort.java b/src/main/java/clap/server/application/port/outbound/notification/LoadNotificationPort.java index 3704ee67..38c80800 100644 --- a/src/main/java/clap/server/application/port/outbound/notification/LoadNotificationPort.java +++ b/src/main/java/clap/server/application/port/outbound/notification/LoadNotificationPort.java @@ -15,4 +15,6 @@ public interface LoadNotificationPort { Optional findById(Long notificationId); Page findAllByReceiverId(Long receiverId, Pageable pageable); + + List findNotificationsByMemberId(Long memberId); } \ No newline at end of file diff --git a/src/main/java/clap/server/application/service/notification/ReadNotificationService.java b/src/main/java/clap/server/application/service/notification/ReadNotificationService.java index ed4ff10b..80e27a7e 100644 --- a/src/main/java/clap/server/application/service/notification/ReadNotificationService.java +++ b/src/main/java/clap/server/application/service/notification/ReadNotificationService.java @@ -10,6 +10,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + @ApplicationService @RequiredArgsConstructor public class ReadNotificationService implements UpdateNotificationUsecase { @@ -26,4 +28,14 @@ public void updateNotification(Long notificationId) { notification.updateNotificationIsRead(); commandNotificationPort.save(notification); } + + @Transactional + @Override + public void updateAllNotification(Long memberId) { + List notificationList = loadNotificationPort.findNotificationsByMemberId(memberId); + for (Notification notification : notificationList) { + notification.updateNotificationIsRead(); + commandNotificationPort.save(notification); + } + } } From 6c50513a468e28b0684d47bbd3d09446d445dd5b Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 26 Jan 2025 21:41:44 +0900 Subject: [PATCH 2/2] =?UTF-8?q?CLAP-145=20Fix:=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=EA=B0=92=EC=9D=84=20Page=EA=B0=80=20Slice=EB=A1=9C=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inbound/web/dto/common/SliceResponse.java | 13 ++++ .../FindNotificationController.java | 4 +- .../NotificationPersistenceAdapter.java | 13 ++-- .../notification/NotificationRepository.java | 4 +- .../mapper/NotificationMapper.java | 12 ++++ .../FindNotificationListUsecase.java | 4 +- .../notification/LoadNotificationPort.java | 6 +- .../FindNotificationListService.java | 4 +- .../notification/NotificationServiceTest.java | 68 ------------------- 9 files changed, 44 insertions(+), 84 deletions(-) create mode 100644 src/main/java/clap/server/adapter/inbound/web/dto/common/SliceResponse.java delete mode 100644 src/test/java/clap/server/notification/NotificationServiceTest.java diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/common/SliceResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/common/SliceResponse.java new file mode 100644 index 00000000..3cffcec0 --- /dev/null +++ b/src/main/java/clap/server/adapter/inbound/web/dto/common/SliceResponse.java @@ -0,0 +1,13 @@ +package clap.server.adapter.inbound.web.dto.common; + + +import java.util.List; + +public record SliceResponse ( + List content, + int currentPage, + int size, + boolean isFirst, + boolean isLast +) { +} diff --git a/src/main/java/clap/server/adapter/inbound/web/notification/FindNotificationController.java b/src/main/java/clap/server/adapter/inbound/web/notification/FindNotificationController.java index 0af8e4c3..245648ec 100644 --- a/src/main/java/clap/server/adapter/inbound/web/notification/FindNotificationController.java +++ b/src/main/java/clap/server/adapter/inbound/web/notification/FindNotificationController.java @@ -1,6 +1,7 @@ package clap.server.adapter.inbound.web.notification; import clap.server.adapter.inbound.security.SecurityUserDetails; +import clap.server.adapter.inbound.web.dto.common.SliceResponse; import clap.server.adapter.inbound.web.dto.notification.FindNotificationListResponse; import clap.server.application.port.inbound.notification.FindNotificationListUsecase; import clap.server.common.annotation.architecture.WebAdapter; @@ -9,7 +10,6 @@ import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; @@ -34,7 +34,7 @@ public class FindNotificationController { @Parameter(name = "size", description = "조회할 목록 페이지 당 개수", example = "5", required = false) }) @GetMapping - public ResponseEntity> findNotificationList( + public ResponseEntity> findNotificationList( @AuthenticationPrincipal SecurityUserDetails securityUserDetails, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "5") int size) { diff --git a/src/main/java/clap/server/adapter/outbound/persistense/NotificationPersistenceAdapter.java b/src/main/java/clap/server/adapter/outbound/persistense/NotificationPersistenceAdapter.java index 40e0f5de..b7330bd0 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/NotificationPersistenceAdapter.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/NotificationPersistenceAdapter.java @@ -1,5 +1,6 @@ package clap.server.adapter.outbound.persistense; +import clap.server.adapter.inbound.web.dto.common.SliceResponse; import clap.server.adapter.inbound.web.dto.notification.FindNotificationListResponse; import clap.server.adapter.outbound.persistense.mapper.NotificationPersistenceMapper; import clap.server.adapter.outbound.persistense.repository.notification.NotificationRepository; @@ -9,8 +10,8 @@ import clap.server.common.annotation.architecture.PersistenceAdapter; import clap.server.domain.model.notification.Notification; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import java.util.List; import java.util.Optional; @@ -31,10 +32,14 @@ public Optional findById(Long notificationId) { } @Override - public Page findAllByReceiverId(Long receiverId, Pageable pageable) { - Page notificationList = notificationRepository.findAllByReceiver_MemberId(receiverId, pageable) + public SliceResponse findAllByReceiverId(Long receiverId, Pageable pageable) { + Slice notificationList = notificationRepository + .findAllByReceiver_MemberIdOrderByCreatedAtDesc(receiverId, pageable) .map(notificationPersistenceMapper::toDomain); - return notificationList.map(NotificationMapper::toFindNoticeListResponse); + + return NotificationMapper.toSliceOfFindNoticeListResponse( + notificationList.map(NotificationMapper::toFindNoticeListResponse) + ); } @Override diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/notification/NotificationRepository.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/notification/NotificationRepository.java index 37aebd57..0239cd44 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/notification/NotificationRepository.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/notification/NotificationRepository.java @@ -1,8 +1,8 @@ package clap.server.adapter.outbound.persistense.repository.notification; import clap.server.adapter.outbound.persistense.entity.notification.NotificationEntity; -import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -12,7 +12,7 @@ @Repository public interface NotificationRepository extends JpaRepository { - Page findAllByReceiver_MemberId(Long receiverId, Pageable pageable); + Slice findAllByReceiver_MemberIdOrderByCreatedAtDesc(Long receiverId, Pageable pageable); List findAllByReceiver_MemberId(Long memberId); } \ No newline at end of file diff --git a/src/main/java/clap/server/application/mapper/NotificationMapper.java b/src/main/java/clap/server/application/mapper/NotificationMapper.java index fb793d2c..d53d71b4 100644 --- a/src/main/java/clap/server/application/mapper/NotificationMapper.java +++ b/src/main/java/clap/server/application/mapper/NotificationMapper.java @@ -1,7 +1,9 @@ package clap.server.application.mapper; +import clap.server.adapter.inbound.web.dto.common.SliceResponse; import clap.server.adapter.inbound.web.dto.notification.FindNotificationListResponse; import clap.server.domain.model.notification.Notification; +import org.springframework.data.domain.Slice; public class NotificationMapper { private NotificationMapper() {throw new IllegalArgumentException();} @@ -17,4 +19,14 @@ public static FindNotificationListResponse toFindNoticeListResponse(Notification notification.getCreatedAt() ); } + + public static SliceResponse toSliceOfFindNoticeListResponse(Slice slice) { + return new SliceResponse<>( + slice.getContent(), + slice.getNumber(), + slice.getSize(), + slice.isFirst(), + slice.isLast() + ); + } } diff --git a/src/main/java/clap/server/application/port/inbound/notification/FindNotificationListUsecase.java b/src/main/java/clap/server/application/port/inbound/notification/FindNotificationListUsecase.java index 26196d1b..4b6f96ac 100644 --- a/src/main/java/clap/server/application/port/inbound/notification/FindNotificationListUsecase.java +++ b/src/main/java/clap/server/application/port/inbound/notification/FindNotificationListUsecase.java @@ -1,9 +1,9 @@ package clap.server.application.port.inbound.notification; +import clap.server.adapter.inbound.web.dto.common.SliceResponse; import clap.server.adapter.inbound.web.dto.notification.FindNotificationListResponse; -import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; public interface FindNotificationListUsecase { - Page findNotificationList(Long receiverId, Pageable pageable); + SliceResponse findNotificationList(Long receiverId, Pageable pageable); } diff --git a/src/main/java/clap/server/application/port/outbound/notification/LoadNotificationPort.java b/src/main/java/clap/server/application/port/outbound/notification/LoadNotificationPort.java index 38c80800..8954c40d 100644 --- a/src/main/java/clap/server/application/port/outbound/notification/LoadNotificationPort.java +++ b/src/main/java/clap/server/application/port/outbound/notification/LoadNotificationPort.java @@ -1,11 +1,9 @@ package clap.server.application.port.outbound.notification; +import clap.server.adapter.inbound.web.dto.common.SliceResponse; import clap.server.adapter.inbound.web.dto.notification.FindNotificationListResponse; -import clap.server.adapter.outbound.persistense.entity.notification.NotificationEntity; import clap.server.domain.model.notification.Notification; -import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; - import java.util.List; import java.util.Optional; @@ -14,7 +12,7 @@ public interface LoadNotificationPort { Optional findById(Long notificationId); - Page findAllByReceiverId(Long receiverId, Pageable pageable); + SliceResponse findAllByReceiverId(Long receiverId, Pageable pageable); List findNotificationsByMemberId(Long memberId); } \ No newline at end of file diff --git a/src/main/java/clap/server/application/service/notification/FindNotificationListService.java b/src/main/java/clap/server/application/service/notification/FindNotificationListService.java index 85902515..5b352e10 100644 --- a/src/main/java/clap/server/application/service/notification/FindNotificationListService.java +++ b/src/main/java/clap/server/application/service/notification/FindNotificationListService.java @@ -1,11 +1,11 @@ package clap.server.application.service.notification; +import clap.server.adapter.inbound.web.dto.common.SliceResponse; import clap.server.adapter.inbound.web.dto.notification.FindNotificationListResponse; import clap.server.application.port.inbound.notification.FindNotificationListUsecase; import clap.server.application.port.outbound.notification.LoadNotificationPort; import clap.server.common.annotation.architecture.ApplicationService; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.transaction.annotation.Transactional; @@ -18,7 +18,7 @@ public class FindNotificationListService implements FindNotificationListUsecase @Override - public Page findNotificationList(Long receiverId, Pageable pageable) { + public SliceResponse findNotificationList(Long receiverId, Pageable pageable) { return loadNotificationPort.findAllByReceiverId(receiverId, pageable); } } diff --git a/src/test/java/clap/server/notification/NotificationServiceTest.java b/src/test/java/clap/server/notification/NotificationServiceTest.java deleted file mode 100644 index ae79627b..00000000 --- a/src/test/java/clap/server/notification/NotificationServiceTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package clap.server.notification; - -import clap.server.adapter.inbound.web.dto.notification.FindNotificationListResponse; -import clap.server.adapter.outbound.persistense.entity.notification.constant.NotificationType; -import clap.server.application.port.outbound.notification.LoadNotificationPort; -import clap.server.application.service.notification.FindNotificationListService; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.testcontainers.junit.jupiter.Testcontainers; - -import java.time.LocalDateTime; -import java.util.List; - -import static org.mockito.Mockito.when; - -@Testcontainers -@ExtendWith(MockitoExtension.class) -public class NotificationServiceTest { - - @Mock - private LoadNotificationPort loadNotificationPort; - - @InjectMocks - private FindNotificationListService findNotificationListService; - - - @Test - public void testFindNotificationList() { - //Given - // 목록 조회 테스트이므로 여러개의 데이터를 List에 저장 - FindNotificationListResponse findNotificationListResponse = new FindNotificationListResponse( - 1L, 1L, NotificationType.PROCESSOR_ASSIGNED, 1L, "VM 생성해주세요", "이규동", LocalDateTime.now() - ); - FindNotificationListResponse findNotificationListResponse2 = new FindNotificationListResponse( - 1L, 1L, NotificationType.PROCESSOR_CHANGED, 1L, "VM 생성해주세요", "이규동", LocalDateTime.now() - ); - FindNotificationListResponse findNotificationListResponse3 = new FindNotificationListResponse( - 1L, 1L, NotificationType.STATUS_SWITCHED, 1L, "VM 생성해주세요", "진행중", LocalDateTime.now() - ); - - List notificationList = List.of( - findNotificationListResponse, findNotificationListResponse2, findNotificationListResponse3 - ); - - Page page = new PageImpl<>(notificationList); - Pageable pageable = Pageable.ofSize(3); - - //Mock - when(loadNotificationPort.findAllByReceiverId(1L, pageable)).thenReturn(page); - - //When - Page result = findNotificationListService.findNotificationList(1L, pageable); - - //Then - Assertions.assertEquals(3, result.getContent().size()); - - Assertions.assertEquals("VM 생성해주세요", result.getContent().get(0).taskTitle()); - Assertions.assertEquals("VM 생성해주세요", result.getContent().get(1).taskTitle()); - Assertions.assertEquals("VM 생성해주세요", result.getContent().get(2).taskTitle()); - } -}