From 14d09d22b655c834e4213e86f419c08121c91c16 Mon Sep 17 00:00:00 2001 From: ghdcksgml1 Date: Wed, 13 Sep 2023 12:42:41 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat(#41):=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=ED=99=95=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 5 +++- .../heachi/mongo/define/notify/Notify.java | 5 ++-- .../api/controller/NotifyController.java | 18 +++++++++++++ .../api/service/notify/NotifyService.java | 20 +++++++++++---- .../NotifyServiceReceiverResponse.java | 25 +++++++++++-------- .../common/exception/ExceptionMessage.java | 2 ++ .../exception/notify/NotifyException.java | 10 ++++++++ 7 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 heachi-support/common/src/main/java/com/heachi/admin/common/exception/notify/NotifyException.java diff --git a/gradle.properties b/gradle.properties index c0d165dc..48354356 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,4 +8,7 @@ projectGroup=com.heachi kotlinVersion=1.6.21 springBootVersion=3.1.2 springDependencyManagementVersion=1.1.2 -springCloudDependenciesVersion=2022.0.3 \ No newline at end of file +springCloudDependenciesVersion=2022.0.3 + +DOCKER_USERNAME= +DOCKER_PASSWORD= \ No newline at end of file diff --git a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/Notify.java b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/Notify.java index 2be83046..d2593f6e 100644 --- a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/Notify.java +++ b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/Notify.java @@ -41,7 +41,8 @@ private Notify(String sendUserId, List receiveUserIds, NotifyType type, this.checked = checked; } - public void receiverUserCheckedNotify() { - + public void receiverUserCheckedNotify(String receiverUserId) { + checked.add(receiverUserId); + checkedTime.put(receiverUserId, LocalDateTime.now()); } } diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java b/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java index 203f86f8..f17b6740 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java @@ -27,6 +27,9 @@ public class NotifyController { private final NotifyService notifyService; private final AuthService authService; + /** + * 알림 구독하기 (Server Sent Event 방식) + */ @GetMapping(value = "/", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux receive(@RequestHeader(value = "Authorization", required = false, defaultValue = "token") String headers) { @@ -35,6 +38,9 @@ public Flux receive(@RequestHeader(value = "Authorization", required .subscribeOn(Schedulers.boundedElastic()); // publisher의 스케줄러를 boundedElastic으로 변경 } + /** + * 알림 추가하기 + */ @PostMapping("/") public Mono registNotify( @RequestHeader(value = "Authorization", required = false, defaultValue = "token") String headers, @@ -45,4 +51,16 @@ public Mono registNotify( .thenReturn(JsonResult.successOf())) .subscribeOn(Schedulers.boundedElastic()); // publisher의 스케줄러를 boundedElastic으로 변경 } + + /** + * 사용자 알림 읽기 이벤트 + */ + @GetMapping("/read/{notifyId}") + public Mono readNotify( + @RequestHeader(value = "Authorization", required = false, defaultValue = "token") String headers, + @PathVariable("notifyId") String notifyId) { + return authService.getUserId(headers) + .flatMap(userId -> notifyService.readNotify(userId, notifyId)) + .subscribeOn(Schedulers.boundedElastic()); + } } diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java index 3f022a7f..8e6479f4 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java @@ -1,5 +1,7 @@ package com.heachi.notify.api.service.notify; +import com.heachi.admin.common.exception.ExceptionMessage; +import com.heachi.admin.common.exception.notify.NotifyException; import com.heachi.admin.common.response.JsonResult; import com.heachi.mongo.define.notify.Notify; import com.heachi.mongo.define.notify.repository.NotifyRepository; @@ -7,6 +9,7 @@ import com.heachi.notify.api.service.notify.response.NotifyServiceReceiverResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -22,11 +25,8 @@ public class NotifyService { public Flux receive(String receiverId) { return notifyRepository.findByReceiveUserIds(receiverId) - .flatMap(notify -> { - NotifyServiceReceiverResponse nsrr = NotifyServiceReceiverResponse.of(notify); - - return Flux.just(JsonResult.successOf(nsrr)); - }) + .doOnCancel(() -> System.out.println(">>>>>>>cancel!!!!!!!!!!")) + .flatMap(notify -> Flux.just(JsonResult.successOf(NotifyServiceReceiverResponse.of(notify, receiverId)))) .timeout(Duration.ofSeconds(30)) .onErrorReturn(TimeoutException.class, JsonResult.failOf("Timeout")); // 30초가 지나면 타임아웃 } @@ -34,4 +34,14 @@ public Flux receive(String receiverId) { public Mono registNotify(NotifyServiceRegistRequest request) { return notifyRepository.save(request.toEntity()); } + + public Mono readNotify(String userId, String notifyId) { + return notifyRepository.findById(notifyId) + .switchIfEmpty(Mono.error(new NotifyException(ExceptionMessage.NOTIFY_NOT_FOUND))) + .flatMap(notify -> { + notify.receiverUserCheckedNotify(userId); // 알림 확인 체크 + return notifyRepository.save(notify); + }) + .map(notify -> JsonResult.successOf(NotifyServiceReceiverResponse.of(notify, userId))); + } } diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/response/NotifyServiceReceiverResponse.java b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/response/NotifyServiceReceiverResponse.java index 8dc5ffdf..2b88438c 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/response/NotifyServiceReceiverResponse.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/response/NotifyServiceReceiverResponse.java @@ -13,21 +13,23 @@ @Getter @ToString public class NotifyServiceReceiverResponse { + private String id; private String sendUserId; // 알림을 보낸 유저 아이디 - private List receiveUserIds = new ArrayList<>(); // 알림을 받는 아이디 + private String receiveUserIds; // 알림을 받는 아이디 private NotifyType type; // 알림 종류 private String message; // 알림 내용 private String generatedUrl; // 알림의 근원지 private String url; // 알림 클릭 시 이동할 주소 - private LocalDateTime createdTime = LocalDateTime.now(); // 알림 발생 시간 - private Map checkedTime = new HashMap<>(); // 알림 확인 시간 - private Set checked = new HashSet<>(); // 알림을 확인했는지 안했는지 + private LocalDateTime createdTime; // 알림 발생 시간 + private LocalDateTime checkedTime; // 알림 확인 시간 + private boolean checked; // 알림을 확인했는지 안했는지 private String dateDistance; // 얼마나 지난 알림인지 @Builder - private NotifyServiceReceiverResponse(String sendUserId, List receiveUserIds, NotifyType type, String message - , String generatedUrl, String url, LocalDateTime createdTime, Map checkedTime - , Set checked, String dateDistance) { + public NotifyServiceReceiverResponse(String id, String sendUserId, String receiveUserIds, NotifyType type, + String message, String generatedUrl, String url, LocalDateTime createdTime, + LocalDateTime checkedTime, boolean checked, String dateDistance) { + this.id = id; this.sendUserId = sendUserId; this.receiveUserIds = receiveUserIds; this.type = type; @@ -40,17 +42,18 @@ private NotifyServiceReceiverResponse(String sendUserId, List receiveUse this.dateDistance = dateDistance; } - public static NotifyServiceReceiverResponse of(Notify notify) { + public static NotifyServiceReceiverResponse of(Notify notify, String receiveUserId) { return NotifyServiceReceiverResponse.builder() + .id(notify.getId()) .sendUserId(notify.getSendUserId()) - .receiveUserIds(notify.getReceiveUserIds()) + .receiveUserIds(receiveUserId) .type(notify.getType()) .message(notify.getMessage()) .generatedUrl(notify.getGeneratedUrl()) .url(notify.getUrl()) .createdTime(notify.getCreatedTime()) - .checkedTime(notify.getCheckedTime()) - .checked(notify.getChecked()) + .checkedTime(notify.getCheckedTime().get(receiveUserId)) + .checked(notify.getChecked().contains(receiveUserId)) .dateDistance(DateDistance.of(notify.getCreatedTime())) .build(); } diff --git a/heachi-support/common/src/main/java/com/heachi/admin/common/exception/ExceptionMessage.java b/heachi-support/common/src/main/java/com/heachi/admin/common/exception/ExceptionMessage.java index 1d09afbe..c24a5ee7 100644 --- a/heachi-support/common/src/main/java/com/heachi/admin/common/exception/ExceptionMessage.java +++ b/heachi-support/common/src/main/java/com/heachi/admin/common/exception/ExceptionMessage.java @@ -22,6 +22,8 @@ public enum ExceptionMessage { // AuthException AUTH_SERVER_NOT_RESPOND("인증 서버가 응답하지 않습니다."), + // NotifyException + NOTIFY_NOT_FOUND("해당 아이디의 알림을 찾을 수 없습니다."), ; private final String text; diff --git a/heachi-support/common/src/main/java/com/heachi/admin/common/exception/notify/NotifyException.java b/heachi-support/common/src/main/java/com/heachi/admin/common/exception/notify/NotifyException.java new file mode 100644 index 00000000..8bc2edf1 --- /dev/null +++ b/heachi-support/common/src/main/java/com/heachi/admin/common/exception/notify/NotifyException.java @@ -0,0 +1,10 @@ +package com.heachi.admin.common.exception.notify; + +import com.heachi.admin.common.exception.ExceptionMessage; +import com.heachi.admin.common.exception.HeachiException; + +public class NotifyException extends HeachiException { + public NotifyException(ExceptionMessage message) { + super(message.getText()); + } +} From ac324f6535515e3843ba1f2ed028d798dbeae3ce Mon Sep 17 00:00:00 2001 From: ghdcksgml1 Date: Thu, 14 Sep 2023 21:58:16 +0900 Subject: [PATCH 2/9] =?UTF-8?q?refactor(#41):=20update=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=97=90=20receiverUserId=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/heachi/mongo/define/notify/Notify.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/Notify.java b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/Notify.java index d2593f6e..80673d5b 100644 --- a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/Notify.java +++ b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/Notify.java @@ -4,6 +4,7 @@ import lombok.Builder; import lombok.Getter; import lombok.ToString; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @@ -13,6 +14,7 @@ @Getter @ToString @Document(collection = "notify") +@Slf4j public class Notify { @Id private String id; @@ -42,6 +44,16 @@ private Notify(String sendUserId, List receiveUserIds, NotifyType type, } public void receiverUserCheckedNotify(String receiverUserId) { + // receiver에 해당 사용자가 있는지 확인한다. + this.receiveUserIds.stream() + .filter(id -> id.equals(receiverUserId)) + .findFirst() + .orElseThrow(() -> { + log.error(">>>> ReceiverIds에 해당 사용자가 존재하지 않습니다 : {}", receiverUserId); + throw new IllegalArgumentException(); + }); + + // 있다면, 체크표시 checked.add(receiverUserId); checkedTime.put(receiverUserId, LocalDateTime.now()); } From 77472795b0ff584d14464517f235cc97ea44e482 Mon Sep 17 00:00:00 2001 From: ghdcksgml1 Date: Thu, 14 Sep 2023 21:59:45 +0900 Subject: [PATCH 3/9] refactor(#41): ReactiveMongoRepository -> ReactiveMongoTemplate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ReactiveMongoTemplate을 이용한 페이지 네이션으로 변경 --- .../notify/repository/NotifyRepository.java | 5 +-- .../repository/NotifyRepositoryCustom.java | 10 ++++++ .../repository/NotifyRepositoryImpl.java | 34 +++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryCustom.java create mode 100644 heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryImpl.java diff --git a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepository.java b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepository.java index 9f405c07..a7a64c33 100644 --- a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepository.java +++ b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepository.java @@ -8,9 +8,6 @@ import reactor.core.publisher.Flux; @Repository -public interface NotifyRepository extends ReactiveMongoRepository { +public interface NotifyRepository extends ReactiveMongoRepository, NotifyRepositoryCustom { - @Tailable - @Query("{ receiveUserIds : ?0 }") - public Flux findByReceiveUserIds(String userIds); } diff --git a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryCustom.java b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryCustom.java new file mode 100644 index 00000000..2b03dcce --- /dev/null +++ b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryCustom.java @@ -0,0 +1,10 @@ +package com.heachi.mongo.define.notify.repository; + +import com.heachi.mongo.define.notify.Notify; +import reactor.core.publisher.Flux; + +public interface NotifyRepositoryCustom { + + public Flux findNotifyByReceiveUserIdsPaging(String userIds, int page); + +} diff --git a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryImpl.java b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryImpl.java new file mode 100644 index 00000000..5f3bcb26 --- /dev/null +++ b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryImpl.java @@ -0,0 +1,34 @@ +package com.heachi.mongo.define.notify.repository; + +import com.heachi.mongo.define.notify.Notify; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class NotifyRepositoryImpl implements NotifyRepositoryCustom { + + private final ReactiveMongoTemplate mongoTemplate; + + @Override + public Flux findNotifyByReceiveUserIdsPaging(String userIds, int page) { + return Mono.just(PageRequest.of(page, 10, Sort.by("createdTime").descending())) + .map(pageable -> { + Query query = new Query() + .with(pageable); + query.addCriteria(Criteria.where("receiveUserIds").in(List.of(userIds))); + + return query; + } + ).flatMapMany(query -> mongoTemplate.find(query, Notify.class, "notify")); + } +} From a3ddb5c21c18f4ca6c01379ce378bb887cdd1868 Mon Sep 17 00:00:00 2001 From: ghdcksgml1 Date: Thu, 14 Sep 2023 22:00:50 +0900 Subject: [PATCH 4/9] =?UTF-8?q?delete(#41):=20MongoDB=20Cursor=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=20=EB=B6=80=EB=B6=84=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/heachi/mongo/config/JpaConfig.java | 14 -- .../java/com/heachi/mongo/TestConnection.java | 40 ----- .../heachi/mongo/config/JpaConfigTest.java | 17 -- .../repository/NotifyRepositoryTest.java | 43 ++++-- .../api/service/notify/NotifyServiceTest.java | 145 +++++++++--------- 5 files changed, 101 insertions(+), 158 deletions(-) delete mode 100644 heachi-domain-mongo/src/test/java/com/heachi/mongo/TestConnection.java diff --git a/heachi-domain-mongo/src/main/java/com/heachi/mongo/config/JpaConfig.java b/heachi-domain-mongo/src/main/java/com/heachi/mongo/config/JpaConfig.java index b79aacbd..a8db286a 100644 --- a/heachi-domain-mongo/src/main/java/com/heachi/mongo/config/JpaConfig.java +++ b/heachi-domain-mongo/src/main/java/com/heachi/mongo/config/JpaConfig.java @@ -19,18 +19,4 @@ @RequiredArgsConstructor public class JpaConfig { - private final ReactiveMongoTemplate reactiveMongoTemplate; - - // notify Collection Setting - @Bean - public void mongoDBinit() { - // Collection 초기 세팅을 위해 Notify 객체를 생성했다가 지움 - reactiveMongoTemplate.insert(Notify.builder().build()) - .flatMap(notify -> reactiveMongoTemplate.remove(notify) - .then(reactiveMongoTemplate.executeCommand("{ convertToCapped: 'notify', size: 8192 }")) - .then(reactiveMongoTemplate.executeCommand("{ collStats: 'notify' }")) - .doOnNext(stats -> System.out.println("stats = " + stats)) - ) - .subscribe(); - } } \ No newline at end of file diff --git a/heachi-domain-mongo/src/test/java/com/heachi/mongo/TestConnection.java b/heachi-domain-mongo/src/test/java/com/heachi/mongo/TestConnection.java deleted file mode 100644 index 9f8587e1..00000000 --- a/heachi-domain-mongo/src/test/java/com/heachi/mongo/TestConnection.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.heachi.mongo; - -import com.mongodb.reactivestreams.client.MongoClient; -import org.bson.Document; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.ReactiveMongoTemplate; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -public class TestConnection extends TestConfig { - - @Autowired - private ReactiveMongoTemplate reactiveMongoTemplate; - - @Test - @DisplayName("MongoDB에 컬렉션을 고정된 크기로 고정시키기 위해 capped 설정을 해준다.") - void mongoDBcappedConfiguration() { - // given - reactiveMongoTemplate.executeCommand("{ convertToCapped: 'notify', size: 8192 }"); - - // when - reactiveMongoTemplate.executeCommand("{ collStats: 'notify' }") - // then - .as(StepVerifier::create) - .expectNextMatches(document -> { - assertThat(document.get("capped")).isEqualTo(true); - assertThat(document.get("totalSize")).isEqualTo(8192); - - return true; - }) - .verifyComplete(); - } -} diff --git a/heachi-domain-mongo/src/test/java/com/heachi/mongo/config/JpaConfigTest.java b/heachi-domain-mongo/src/test/java/com/heachi/mongo/config/JpaConfigTest.java index 562c1953..60224f6d 100644 --- a/heachi-domain-mongo/src/test/java/com/heachi/mongo/config/JpaConfigTest.java +++ b/heachi-domain-mongo/src/test/java/com/heachi/mongo/config/JpaConfigTest.java @@ -14,22 +14,5 @@ @SpringBootTest class JpaConfigTest extends TestConfig { - @Autowired - private ReactiveMongoTemplate reactiveMongoTemplate; - @Test - @DisplayName("Spring Applicatoin이 띄워질때, MongoDB capped 설정이 true가 된다.") - void mongoDBConfigurationInitialized() { - // when - reactiveMongoTemplate.executeCommand("{ collStats: 'notify' }") - // then - .as(StepVerifier::create) - .expectNextMatches(document -> { - assertThat(document.get("capped")).isEqualTo(true); - assertThat(document.get("totalSize")).isEqualTo(8192); - - return true; - }) - .verifyComplete(); - } } \ No newline at end of file diff --git a/heachi-domain-mongo/src/test/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryTest.java b/heachi-domain-mongo/src/test/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryTest.java index 506926dd..2b7e1cb6 100644 --- a/heachi-domain-mongo/src/test/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryTest.java +++ b/heachi-domain-mongo/src/test/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryTest.java @@ -2,10 +2,7 @@ import com.heachi.mongo.TestConfig; import com.heachi.mongo.define.notify.Notify; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import reactor.core.publisher.Flux; @@ -13,6 +10,9 @@ import reactor.core.scheduler.Schedulers; import reactor.test.StepVerifier; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -26,9 +26,10 @@ class NotifyRepositoryTest extends TestConfig { @AfterEach void tearDown() { - notifyRepository.deleteAll(); + notifyRepository.deleteAll().subscribe(); } + @Test @DisplayName("Notify 객체를 만들어 저장할 수 있다.") void saveTest() { @@ -50,18 +51,30 @@ void saveTest() { } @Test - @Disabled - @DisplayName("ReceiveUserIds 리스트에 ReceiveUserId가 존재하면 해당 Notify를 반환한다.") - void findByReceiveUserIds() { + @DisplayName("ReceiveUserId를 넣고, 페이지를 넣으면 해당 페이지의 Notify가 10개가 나온다.") + void selectNotifyWhereReceiveUserIdLimit10Pagination() { // given - Notify notify = Notify.builder() - .sendUserId("홍찬희") - .receiveUserIds(List.of("ghdcksgml1", "ghdcksgml2", "ghdcksgml3")) - .build(); + List list = new ArrayList<>(); + for (int i=0; i<10; i++) { + Notify notify = Notify.builder() + .sendUserId("ghdcksgml") + .receiveUserIds(List.of("ghdcksgml1")) + .createdTime(LocalDateTime.now()) + .build(); + list.add(notify); + } + + + Flux flux1 = notifyRepository.saveAll(list); + Flux flux2 = notifyRepository.findNotifyByReceiveUserIdsPaging("ghdcksgml1", 0); + // when - Mono save = notifyRepository.save(notify); - Flux ghdcksgml1 = notifyRepository.findByReceiveUserIds("ghdcksgml1"); - assertThat(ghdcksgml1.collectList().block()).isEqualTo(notify.getSendUserId()); + StepVerifier.create(Flux.concat(flux1, flux2).log()) + // then + .expectSubscription() + .expectNextCount(10) + .expectNextCount(10) + .verifyComplete(); } } \ No newline at end of file diff --git a/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java b/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java index 0435964f..6ea2b9bf 100644 --- a/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java +++ b/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java @@ -45,79 +45,80 @@ void setUp() { notifyRepository.deleteAll().block(); } - @Test - @DisplayName("구독하면, 30초가 커넥션이 유지되고, 30초가 지나면 커넥션은 끊긴다.") - void connection30secondsWhenClientSubscribe() { - // given - - // when - StepVerifier.withVirtualTime(() -> notifyService.receive("2954438047")) - // then - .expectSubscription() // 구독이 시작되고 나서 - .expectNoEvent(Duration.ofSeconds(30)) // 30초간 아무런 응답이 없으면 - .expectNextMatches(jsonResult -> { // 에러를 뱉음 - assertThat(jsonResult.getResCode()).isEqualTo(400); - assertThat(jsonResult.getResMsg()).isEqualTo("Timeout"); - return true; - }) - .verifyComplete(); - } - - @Test - @DisplayName("구독 도중 객체가 추가되었을때 값이 곧바로 반영된다.") - void addNotifyWhenSubscribeOn() { - // given - Notify notify1 = Notify.builder() - .sendUserId("ghdcksgml1") - .receiveUserIds(List.of("ghdcksgml1", "ghdcksgml2", "ghdcksgml3")) - .type(NotifyType.NOTE) - .createdTime(LocalDateTime.now()) - .checkedTime(new HashMap<>()) - .checked(new HashSet<>()) - .build(); - Notify notify2 = Notify.builder() - .sendUserId("ghdcksgml2") - .receiveUserIds(List.of("ghdcksgml1", "ghdcksgml2", "ghdcksgml3")) - .type(NotifyType.NOTE) - .createdTime(LocalDateTime.now()) - .checkedTime(new HashMap<>()) - .checked(new HashSet<>()) - .build(); - Notify notify3 = Notify.builder() - .sendUserId("ghdcksgml3") - .receiveUserIds(List.of("ghdcksgml1", "ghdcksgml2", "ghdcksgml3")) - .type(NotifyType.NOTE) - .createdTime(LocalDateTime.now()) - .checkedTime(new HashMap<>()) - .checked(new HashSet<>()) - .build(); - - notifyRepository.save(notify1).block(); // 매칭되는 아이디가 없으면 Flux가 실행이 안되기 때문에 임의의 데이터를 저장. - - // when - StepVerifier.withVirtualTime(() -> { - Flux event = Mono.delay(Duration.ofSeconds(2)).thenMany(notifyRepository.saveAll(List.of(notify2, notify3))); - Flux flux = notifyService.receive("ghdcksgml1"); - - return Flux.merge(event, flux).log(); - }) - // then - .expectSubscription() - .expectNextCount(1) // 임의의 데이터 1개 - .expectNoEvent(Duration.ofSeconds(2)) // 2초뒤 2개 저장됨 - .expectNextCount(4) // repository.save()가 2번 호출됨, notifyService.receive()에서 2개의 데이터를 바로 받음 - .expectNoEvent(Duration.ofSeconds(30)) // idle 상태가 30초 동안 지속되면 - .expectNextMatches(o -> { - if (o instanceof JsonResult) { - assertThat(((JsonResult) o).getResCode()).isEqualTo(400); - - return true; - } - return false; - }) - .verifyComplete(); - } +// @Test +// @DisplayName("구독하면, 30초가 커넥션이 유지되고, 30초가 지나면 커넥션은 끊긴다.") +// void connection30secondsWhenClientSubscribe() { +// // given +// +// // when +// StepVerifier.withVirtualTime(() -> notifyService.receive("2954438047",0)) +// // then +// .expectSubscription() // 구독이 시작되고 나서 +// .expectNoEvent(Duration.ofSeconds(30)) // 30초간 아무런 응답이 없으면 +// .expectNextMatches(jsonResult -> { // 에러를 뱉음 +// assertThat(jsonResult.getResCode()).isEqualTo(400); +// assertThat(jsonResult.getResMsg()).isEqualTo("Timeout"); +// +// return true; +// }) +// .verifyComplete(); +// } +// +// @Test +// @DisplayName("구독 도중 객체가 추가되었을때 값이 곧바로 반영된다.") +// void addNotifyWhenSubscribeOn() { +// // given +// Notify notify1 = Notify.builder() +// .sendUserId("ghdcksgml1") +// .receiveUserIds(List.of("ghdcksgml1", "ghdcksgml2", "ghdcksgml3")) +// .type(NotifyType.NOTE) +// .createdTime(LocalDateTime.now()) +// .checkedTime(new HashMap<>()) +// .checked(new HashSet<>()) +// .build(); +// Notify notify2 = Notify.builder() +// .sendUserId("ghdcksgml2") +// .receiveUserIds(List.of("ghdcksgml1", "ghdcksgml2", "ghdcksgml3")) +// .type(NotifyType.NOTE) +// .createdTime(LocalDateTime.now()) +// .checkedTime(new HashMap<>()) +// .checked(new HashSet<>()) +// .build(); +// Notify notify3 = Notify.builder() +// .sendUserId("ghdcksgml3") +// .receiveUserIds(List.of("ghdcksgml1", "ghdcksgml2", "ghdcksgml3")) +// .type(NotifyType.NOTE) +// .createdTime(LocalDateTime.now()) +// .checkedTime(new HashMap<>()) +// .checked(new HashSet<>()) +// .build(); +// +// notifyRepository.save(notify1).block(); // 매칭되는 아이디가 없으면 Flux가 실행이 안되기 때문에 임의의 데이터를 저장. +// +// // when +// StepVerifier.withVirtualTime(() -> { +// Flux event = Mono.delay(Duration.ofSeconds(2)).thenMany(notifyRepository.saveAll(List.of(notify2, notify3))); +// Flux flux = notifyService.receive("ghdcksgml1",0); +// +// return Flux.merge(event, flux).log(); +// }) +// // then +// .expectSubscription() +// .expectNextCount(1) // 임의의 데이터 1개 +// .expectNoEvent(Duration.ofSeconds(2)) // 2초뒤 2개 저장됨 +// .expectNextCount(4) // repository.save()가 2번 호출됨, notifyService.receive()에서 2개의 데이터를 바로 받음 +// .expectNoEvent(Duration.ofSeconds(30)) // idle 상태가 30초 동안 지속되면 +// .expectNextMatches(o -> { +// if (o instanceof JsonResult) { +// assertThat(((JsonResult) o).getResCode()).isEqualTo(400); +// +// return true; +// } +// return false; +// }) +// .verifyComplete(); +// } @Test @DisplayName("올바른 데이터를 넣어주면, Notify에 저장되고, ID도 부여된다.") From 170166a3872d6b04fedc23d42bb425775cc38bca Mon Sep 17 00:00:00 2001 From: ghdcksgml1 Date: Thu, 14 Sep 2023 22:04:19 +0900 Subject: [PATCH 5/9] =?UTF-8?q?refactor(#41):=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/NotifyController.java | 22 +++++++++++++--- .../api/service/notify/NotifyService.java | 26 +++++++++++-------- .../common/exception/ExceptionMessage.java | 1 + 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java b/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java index f17b6740..da0ddfa2 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java @@ -1,6 +1,7 @@ package com.heachi.notify.api.controller; import com.heachi.admin.common.exception.ExceptionMessage; +import com.heachi.admin.common.exception.notify.NotifyException; import com.heachi.admin.common.exception.oauth.OAuthException; import com.heachi.admin.common.response.JsonResult; import com.heachi.external.clients.auth.AuthClients; @@ -18,6 +19,7 @@ import java.net.ConnectException; import java.time.Duration; +import java.util.List; @RestController @RequestMapping("/notify") @@ -28,13 +30,15 @@ public class NotifyController { private final AuthService authService; /** - * 알림 구독하기 (Server Sent Event 방식) + * 알림 받기 */ @GetMapping(value = "/", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public Flux receive(@RequestHeader(value = "Authorization", required = false, defaultValue = "token") String headers) { + public Flux receive( + @RequestHeader(value = "Authorization", required = false, defaultValue = "token") String headers, + @RequestParam(name = "page", defaultValue = "0") int page) { return authService.getUserId(headers) - .flatMapMany(sendUserId -> notifyService.receive(sendUserId)) + .flatMapMany(sendUserId -> notifyService.receive(sendUserId, page)) .subscribeOn(Schedulers.boundedElastic()); // publisher의 스케줄러를 boundedElastic으로 변경 } @@ -45,9 +49,16 @@ public Flux receive(@RequestHeader(value = "Authorization", required public Mono registNotify( @RequestHeader(value = "Authorization", required = false, defaultValue = "token") String headers, @RequestBody NotifyRegistRequest request) { + return authService.getUserId(headers) + .flatMap(sendUserId -> + request.getReceiveUserIds().stream().filter(receiverId -> receiverId.equals(sendUserId)) + .findFirst() + .map(id -> Mono.error(new NotifyException(ExceptionMessage.NOTIFY_DUPLICATE_ID))) + .orElseGet(() -> Mono.just(sendUserId)) + ) .flatMap(sendUserId -> notifyService - .registNotify(NotifyServiceRegistRequest.of(request, sendUserId)) + .registNotify(NotifyServiceRegistRequest.of(request, sendUserId.toString())) .thenReturn(JsonResult.successOf())) .subscribeOn(Schedulers.boundedElastic()); // publisher의 스케줄러를 boundedElastic으로 변경 } @@ -59,8 +70,11 @@ public Mono registNotify( public Mono readNotify( @RequestHeader(value = "Authorization", required = false, defaultValue = "token") String headers, @PathVariable("notifyId") String notifyId) { + return authService.getUserId(headers) .flatMap(userId -> notifyService.readNotify(userId, notifyId)) + .onErrorMap(throwable -> new NotifyException(ExceptionMessage.NOTIFY_NOT_FOUND)) + .map(notify -> JsonResult.successOf()) .subscribeOn(Schedulers.boundedElastic()); } } diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java index 8e6479f4..4a2f21dc 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java @@ -15,6 +15,8 @@ import reactor.core.scheduler.Schedulers; import java.time.Duration; +import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeoutException; @Service @@ -23,25 +25,27 @@ public class NotifyService { private final NotifyRepository notifyRepository; - public Flux receive(String receiverId) { - return notifyRepository.findByReceiveUserIds(receiverId) - .doOnCancel(() -> System.out.println(">>>>>>>cancel!!!!!!!!!!")) - .flatMap(notify -> Flux.just(JsonResult.successOf(NotifyServiceReceiverResponse.of(notify, receiverId)))) - .timeout(Duration.ofSeconds(30)) - .onErrorReturn(TimeoutException.class, JsonResult.failOf("Timeout")); // 30초가 지나면 타임아웃 + public Flux receive(String receiverId, int page) { + return notifyRepository.findNotifyByReceiveUserIdsPaging(receiverId, page) + .flatMap(notify -> Flux.just(JsonResult.successOf(NotifyServiceReceiverResponse.of(notify, receiverId)))); } public Mono registNotify(NotifyServiceRegistRequest request) { return notifyRepository.save(request.toEntity()); } - public Mono readNotify(String userId, String notifyId) { + public Mono readNotify(String userId, String notifyId) { return notifyRepository.findById(notifyId) .switchIfEmpty(Mono.error(new NotifyException(ExceptionMessage.NOTIFY_NOT_FOUND))) .flatMap(notify -> { - notify.receiverUserCheckedNotify(userId); // 알림 확인 체크 - return notifyRepository.save(notify); - }) - .map(notify -> JsonResult.successOf(NotifyServiceReceiverResponse.of(notify, userId))); + // 이미 알림 확인했는지 체크 + if (!notify.getChecked().contains(userId)) { + notify.receiverUserCheckedNotify(userId); // 알림 확인 체크 + + return notifyRepository.save(notify); + } else { + return Mono.just(notify); + } + }); } } diff --git a/heachi-support/common/src/main/java/com/heachi/admin/common/exception/ExceptionMessage.java b/heachi-support/common/src/main/java/com/heachi/admin/common/exception/ExceptionMessage.java index c24a5ee7..a761342d 100644 --- a/heachi-support/common/src/main/java/com/heachi/admin/common/exception/ExceptionMessage.java +++ b/heachi-support/common/src/main/java/com/heachi/admin/common/exception/ExceptionMessage.java @@ -24,6 +24,7 @@ public enum ExceptionMessage { // NotifyException NOTIFY_NOT_FOUND("해당 아이디의 알림을 찾을 수 없습니다."), + NOTIFY_DUPLICATE_ID("SendUser와 ReceiveUser가 같습니다."), ; private final String text; From 109f134954e975f90fdba35698f547a8e5283e0e Mon Sep 17 00:00:00 2001 From: ghdcksgml1 Date: Thu, 14 Sep 2023 22:05:42 +0900 Subject: [PATCH 6/9] =?UTF-8?q?setting(#41):=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20import=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/heachi/notify/HeachiNotifyApplication.java | 1 - .../com/heachi/notify/api/controller/NotifyController.java | 7 ------- .../com/heachi/notify/api/service/auth/AuthService.java | 5 ----- .../heachi/notify/api/service/notify/NotifyService.java | 7 ------- .../notify/response/NotifyServiceReceiverResponse.java | 1 - .../notify/config/advice/GlobalExceptionHandler.java | 2 -- 6 files changed, 23 deletions(-) diff --git a/heachi-notify/src/main/java/com/heachi/notify/HeachiNotifyApplication.java b/heachi-notify/src/main/java/com/heachi/notify/HeachiNotifyApplication.java index e9a3285d..f2c5e68a 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/HeachiNotifyApplication.java +++ b/heachi-notify/src/main/java/com/heachi/notify/HeachiNotifyApplication.java @@ -1,6 +1,5 @@ package com.heachi.notify; -import com.heachi.admin.common.utils.DateDistance; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.reactive.config.EnableWebFlux; diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java b/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java index da0ddfa2..381fb619 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/controller/NotifyController.java @@ -2,9 +2,7 @@ import com.heachi.admin.common.exception.ExceptionMessage; import com.heachi.admin.common.exception.notify.NotifyException; -import com.heachi.admin.common.exception.oauth.OAuthException; import com.heachi.admin.common.response.JsonResult; -import com.heachi.external.clients.auth.AuthClients; import com.heachi.notify.api.controller.request.NotifyRegistRequest; import com.heachi.notify.api.service.auth.AuthService; import com.heachi.notify.api.service.notify.request.NotifyServiceRegistRequest; @@ -12,15 +10,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; -import org.springframework.web.reactive.function.client.WebClientRequestException; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; -import java.net.ConnectException; -import java.time.Duration; -import java.util.List; - @RestController @RequestMapping("/notify") @RequiredArgsConstructor diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/service/auth/AuthService.java b/heachi-notify/src/main/java/com/heachi/notify/api/service/auth/AuthService.java index 0a42c1fc..505c4836 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/service/auth/AuthService.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/service/auth/AuthService.java @@ -3,17 +3,12 @@ import com.heachi.admin.common.exception.ExceptionMessage; import com.heachi.admin.common.exception.auth.AuthException; import com.heachi.admin.common.exception.jwt.JwtException; -import com.heachi.admin.common.response.JsonResult; import com.heachi.external.clients.auth.AuthClients; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.web.reactive.function.client.WebClientRequestException; -import reactor.core.Exceptions; import reactor.core.publisher.Mono; -import java.net.ConnectException; - @Slf4j @Service @RequiredArgsConstructor diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java index 4a2f21dc..907ee2c8 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java @@ -9,15 +9,8 @@ import com.heachi.notify.api.service.notify.response.NotifyServiceReceiverResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -import java.time.Duration; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.TimeoutException; @Service @RequiredArgsConstructor diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/response/NotifyServiceReceiverResponse.java b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/response/NotifyServiceReceiverResponse.java index 2b88438c..c0446af0 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/response/NotifyServiceReceiverResponse.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/response/NotifyServiceReceiverResponse.java @@ -8,7 +8,6 @@ import lombok.ToString; import java.time.LocalDateTime; -import java.util.*; @Getter @ToString diff --git a/heachi-notify/src/main/java/com/heachi/notify/config/advice/GlobalExceptionHandler.java b/heachi-notify/src/main/java/com/heachi/notify/config/advice/GlobalExceptionHandler.java index bd6395cb..22afef95 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/config/advice/GlobalExceptionHandler.java +++ b/heachi-notify/src/main/java/com/heachi/notify/config/advice/GlobalExceptionHandler.java @@ -1,10 +1,8 @@ package com.heachi.notify.config.advice; -import com.heachi.admin.common.exception.HeachiException; import com.heachi.admin.common.response.JsonResult; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; -import reactor.core.publisher.Mono; @RestControllerAdvice public class GlobalExceptionHandler { From c9ccb400017cf264fe2a18c71ac6c884cae014bf Mon Sep 17 00:00:00 2001 From: ghdcksgml1 Date: Fri, 15 Sep 2023 08:34:46 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat(#41):=20=ED=95=B4=EB=8B=B9=20notify?= =?UTF-8?q?=EC=9D=98=20receiveUserIds=EC=97=90=20userId=EA=B0=80=20?= =?UTF-8?q?=EC=A1=B4=EC=9E=AC=ED=95=98=EB=A9=B4=20Notify=EB=A5=BC=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20=EC=BF=BC=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notify/repository/NotifyRepositoryCustom.java | 11 ++++++++++- .../notify/repository/NotifyRepositoryImpl.java | 15 +++++++++++---- .../notify/api/service/notify/NotifyService.java | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryCustom.java b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryCustom.java index 2b03dcce..4d1699ca 100644 --- a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryCustom.java +++ b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryCustom.java @@ -2,9 +2,18 @@ import com.heachi.mongo.define.notify.Notify; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; public interface NotifyRepositoryCustom { - public Flux findNotifyByReceiveUserIdsPaging(String userIds, int page); + /** + * userId가 받는 알림을 페이징한다. (ReceiveUserIds In userId) + */ + public Flux findNotifyByReceiveUserIdsPaging(String userId, int page); + + /** + * notifyId로 notify를 검색하는데, userId가 recevierUserIds에 존재하는지 + */ + public Mono findNotifyByIdWhereReceiveUserIdsIn(String userId, String notifyId); } diff --git a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryImpl.java b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryImpl.java index 5f3bcb26..cc8425c1 100644 --- a/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryImpl.java +++ b/heachi-domain-mongo/src/main/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryImpl.java @@ -11,8 +11,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.util.List; - @Component @RequiredArgsConstructor public class NotifyRepositoryImpl implements NotifyRepositoryCustom { @@ -20,15 +18,24 @@ public class NotifyRepositoryImpl implements NotifyRepositoryCustom { private final ReactiveMongoTemplate mongoTemplate; @Override - public Flux findNotifyByReceiveUserIdsPaging(String userIds, int page) { + public Flux findNotifyByReceiveUserIdsPaging(String userId, int page) { return Mono.just(PageRequest.of(page, 10, Sort.by("createdTime").descending())) .map(pageable -> { Query query = new Query() .with(pageable); - query.addCriteria(Criteria.where("receiveUserIds").in(List.of(userIds))); + query.addCriteria(Criteria.where("receiveUserIds").in(userId)); return query; } ).flatMapMany(query -> mongoTemplate.find(query, Notify.class, "notify")); } + + @Override + public Mono findNotifyByIdWhereReceiveUserIdsIn(String userId, String notifyId) { + return Mono.just(new Query().addCriteria(Criteria.where("id").is(notifyId) + .and("receiveUserIds").in(userId))) + .flatMap(query -> mongoTemplate.findOne(query, Notify.class, "notify")); + } + + } diff --git a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java index 907ee2c8..84dd0d20 100644 --- a/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java +++ b/heachi-notify/src/main/java/com/heachi/notify/api/service/notify/NotifyService.java @@ -28,7 +28,7 @@ public Mono registNotify(NotifyServiceRegistRequest request) { } public Mono readNotify(String userId, String notifyId) { - return notifyRepository.findById(notifyId) + return notifyRepository.findNotifyByIdWhereReceiveUserIdsIn(userId, notifyId) .switchIfEmpty(Mono.error(new NotifyException(ExceptionMessage.NOTIFY_NOT_FOUND))) .flatMap(notify -> { // 이미 알림 확인했는지 체크 From f5e0ae08978a26003056dc9c83daaf567734523e Mon Sep 17 00:00:00 2001 From: ghdcksgml1 Date: Fri, 15 Sep 2023 08:35:02 +0900 Subject: [PATCH 8/9] =?UTF-8?q?test(#41):=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/NotifyRepositoryTest.java | 40 +++++++++++++ .../api/service/notify/NotifyServiceTest.java | 60 ++++++++++++++----- 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/heachi-domain-mongo/src/test/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryTest.java b/heachi-domain-mongo/src/test/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryTest.java index 2b7e1cb6..2a4e6673 100644 --- a/heachi-domain-mongo/src/test/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryTest.java +++ b/heachi-domain-mongo/src/test/java/com/heachi/mongo/define/notify/repository/NotifyRepositoryTest.java @@ -77,4 +77,44 @@ void selectNotifyWhereReceiveUserIdLimit10Pagination() { .expectNextCount(10) .verifyComplete(); } + + @Test + @DisplayName("notifyId가 일치하고, receiverUserIds에 나의 요청하는 아이디가 있다면, Notify를 가져온다.") + void selectNotifyWhereNotifyIdAndReceiverUserIdsIn() { + // given + Notify notify = Notify.builder() + .sendUserId("ghdcksgml") + .receiveUserIds(List.of("ghdcksgml1")) + .createdTime(LocalDateTime.now()) + .build(); + + Notify savedNotify = notifyRepository.save(notify).block(); + + // when + StepVerifier.create(notifyRepository.findNotifyByIdWhereReceiveUserIdsIn("ghdcksgml1", savedNotify.getId())) + // then + .expectSubscription() + .expectNextCount(1) + .verifyComplete(); + } + + @Test + @DisplayName("notifyId가 일치하지만, receiverUserIds에 요청하는 아이디가 존재하지 않는다면, 권한이 없으므로 아무것도 리턴되지 않는다.") + void selectNotifyWhereNotifyIdAndReceiverUserIdsInNotMatching() { + // given + Notify notify = Notify.builder() + .sendUserId("ghdcksgml") + .receiveUserIds(List.of("ghdcksgml1")) + .createdTime(LocalDateTime.now()) + .build(); + + Notify savedNotify = notifyRepository.save(notify).block(); + + // when + StepVerifier.create(notifyRepository.findNotifyByIdWhereReceiveUserIdsIn("ghdcksgml", savedNotify.getId())) + // then + .expectSubscription() + .expectNextCount(0) + .verifyComplete(); + } } \ No newline at end of file diff --git a/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java b/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java index 6ea2b9bf..9fac77d3 100644 --- a/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java +++ b/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java @@ -1,35 +1,22 @@ package com.heachi.notify.api.service.notify; -import com.heachi.admin.common.response.JsonResult; import com.heachi.mongo.define.notify.Notify; import com.heachi.mongo.define.notify.constant.NotifyType; import com.heachi.mongo.define.notify.repository.NotifyRepository; import com.heachi.notify.TestConfig; -import com.heachi.notify.api.service.notify.NotifyService; import com.heachi.notify.api.service.notify.request.NotifyServiceRegistRequest; -import com.heachi.notify.api.service.notify.response.NotifyServiceReceiverResponse; import org.junit.jupiter.api.*; -import org.mockito.BDDMockito; -import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Schedulers; import reactor.test.StepVerifier; -import reactor.test.scheduler.VirtualTimeScheduler; -import java.time.Duration; import java.time.LocalDateTime; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.concurrent.TimeoutException; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; @SpringBootTest class NotifyServiceTest extends TestConfig { @@ -125,7 +112,7 @@ void setUp() { void registNotify() { // given NotifyServiceRegistRequest notify = NotifyServiceRegistRequest.builder() - .sendUserId("ghdcksgml1") + .sendUserId("ghdcksgml") .receiveUserIds(List.of("ghdcksgml1", "ghdcksgml2", "ghdcksgml3")) .type(NotifyType.NOTE) .build(); @@ -146,4 +133,49 @@ void registNotify() { }) .verifyComplete(); } + + @Test + @DisplayName("자신이 Receiver로 지정되어 있는 알림을 읽으면 Checked가 true가 된다.") + void notifyReadEvent() { + // given + Notify notify = Notify.builder() + .sendUserId("ghdcksgml") + .receiveUserIds(List.of("ghdcksgml1")) + .checked(new HashSet<>()) + .checkedTime(new HashMap<>()) + .createdTime(LocalDateTime.now()) + .build(); + Notify savedNotify = notifyRepository.save(notify).block(); + + Mono mono = notifyService.readNotify("ghdcksgml1", savedNotify.getId()); + + // when + StepVerifier.create(mono) + // then + .expectSubscription() + .assertNext(notify1 -> assertThat(notify1.getChecked()).contains("ghdcksgml1")) + .verifyComplete(); + } + + + @Test + @DisplayName("findNotifyByIdWhereReceiveUserIdsIn에서 찾은 값이 없다면, NOTIFY_NOT_FOUND 에러를 발생시킨다.") + void notifyReadEventFailWhenFindQueryResultIsNull() { + // given + Notify notify = Notify.builder() + .sendUserId("ghdcksgml") + .receiveUserIds(List.of("ghdcksgml1")) + .createdTime(LocalDateTime.now()) + .build(); + Notify savedNotify = notifyRepository.save(notify).block(); + + Mono mono = notifyService.readNotify("UnKnownUser", savedNotify.getId()); + + // when + StepVerifier.create(mono) + // then + .expectSubscription() + .expectError() + .verify(); + } } \ No newline at end of file From 4aa7735506388fb675f71e5ad364465dc4d98717 Mon Sep 17 00:00:00 2001 From: ghdcksgml1 Date: Fri, 15 Sep 2023 08:42:24 +0900 Subject: [PATCH 9/9] =?UTF-8?q?test(#41):=20=EC=98=A4=ED=83=80=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 --- .../com/heachi/notify/api/service/notify/NotifyServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java b/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java index 9fac77d3..cd13e9ec 100644 --- a/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java +++ b/heachi-notify/src/test/java/com/heachi/notify/api/service/notify/NotifyServiceTest.java @@ -126,7 +126,7 @@ void registNotify() { .expectSubscription() .expectNextMatches(n -> { assertThat(n.getId()).isNotNull(); - assertThat(n.getSendUserId()).isEqualTo("ghdcksgml1"); + assertThat(n.getSendUserId()).isEqualTo("ghdcksgml"); assertThat(n.getType()).isEqualTo(NotifyType.NOTE); return true;