From 5e63ce0992e2e4a1f9b3f1e0a067deda8deba148 Mon Sep 17 00:00:00 2001 From: seulki Date: Mon, 7 Oct 2024 13:34:35 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor:=20Task=EC=97=90=20reminderEnabled?= =?UTF-8?q?=20=EC=86=8D=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/taskbuddy/core/database/entity/TaskEntity.java | 7 ++++++- core/src/main/java/com/taskbuddy/core/domain/Task.java | 9 +++++++-- .../com/taskbuddy/core/domain/TaskContentUpdate.java | 1 + .../main/java/com/taskbuddy/core/domain/TaskCreate.java | 1 + .../java/com/taskbuddy/core/service/TaskServiceTest.java | 2 ++ 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/taskbuddy/core/database/entity/TaskEntity.java b/core/src/main/java/com/taskbuddy/core/database/entity/TaskEntity.java index b74c441..46d8b1f 100644 --- a/core/src/main/java/com/taskbuddy/core/database/entity/TaskEntity.java +++ b/core/src/main/java/com/taskbuddy/core/database/entity/TaskEntity.java @@ -28,18 +28,21 @@ public class TaskEntity { private LocalDateTime endDateTime; + private Boolean isReminderEnabled; + private LocalDateTime createdAt; private LocalDateTime updatedAt; @Builder - private TaskEntity(Long id, String title, Boolean isDone, String description, LocalDateTime startDateTime, LocalDateTime endDateTime, LocalDateTime createdAt, LocalDateTime updatedAt) { + private TaskEntity(Long id, String title, Boolean isDone, String description, LocalDateTime startDateTime, LocalDateTime endDateTime, Boolean isReminderEnabled, LocalDateTime createdAt, LocalDateTime updatedAt) { this.id = id; this.title = title; this.isDone = isDone; this.description = description; this.startDateTime = startDateTime; this.endDateTime = endDateTime; + this.isReminderEnabled = isReminderEnabled; this.createdAt = createdAt; this.updatedAt = updatedAt; } @@ -52,6 +55,7 @@ public static TaskEntity from(Task task) { .description(task.getDescription()) .startDateTime(task.getTimeFrame().startDateTime()) .endDateTime(task.getTimeFrame().endDateTime()) + .isReminderEnabled(task.isReminderEnabled()) .createdAt(task.getCreatedAt()) .updatedAt(task.getUpdatedAt()) .build(); @@ -64,6 +68,7 @@ public Task toModel() { .isDone(isDone) .description(description) .timeFrame(new TimeFrame(startDateTime, endDateTime)) + .reminderEnabled(isReminderEnabled) .createdAt(createdAt) .updatedAt(updatedAt) .build(); diff --git a/core/src/main/java/com/taskbuddy/core/domain/Task.java b/core/src/main/java/com/taskbuddy/core/domain/Task.java index 05b22a5..9b7c716 100644 --- a/core/src/main/java/com/taskbuddy/core/domain/Task.java +++ b/core/src/main/java/com/taskbuddy/core/domain/Task.java @@ -9,21 +9,24 @@ @Getter public class Task { private final Long id; -// private User user; + private User user; private String title; private Boolean isDone; private String description; private TimeFrame timeFrame; + private boolean reminderEnabled; private final LocalDateTime createdAt; private LocalDateTime updatedAt; @Builder - public Task(Long id, String title, Boolean isDone, String description, TimeFrame timeFrame, LocalDateTime createdAt, LocalDateTime updatedAt) { + public Task(Long id, User user, String title, Boolean isDone, String description, TimeFrame timeFrame, boolean reminderEnabled, LocalDateTime createdAt, LocalDateTime updatedAt) { this.id = id; + this.user = user; this.title = title; this.isDone = isDone; this.description = description; this.timeFrame = timeFrame; + this.reminderEnabled = reminderEnabled; this.createdAt = createdAt; this.updatedAt = updatedAt; } @@ -37,6 +40,7 @@ public static Task from(TaskCreate taskCreate, ClockHolder clockHolder) { .isDone(isDoneDefaultValue) .description(taskCreate.description()) .timeFrame(new TimeFrame(taskCreate.startDateTime(), taskCreate.endDateTime())) + .reminderEnabled(taskCreate.reminderEnabled()) .createdAt(createdAt) .updatedAt(createdAt) .build(); @@ -46,6 +50,7 @@ public void update(TaskContentUpdate taskContentUpdate, ClockHolder clockHolder) title = taskContentUpdate.title(); description = taskContentUpdate.description(); timeFrame = new TimeFrame(taskContentUpdate.startDateTime(), taskContentUpdate.endDateTime()); + reminderEnabled = taskContentUpdate.reminderEnabled(); updatedAt = clockHolder.currentDateTime(); } diff --git a/core/src/main/java/com/taskbuddy/core/domain/TaskContentUpdate.java b/core/src/main/java/com/taskbuddy/core/domain/TaskContentUpdate.java index 6f7d199..cff1f4b 100644 --- a/core/src/main/java/com/taskbuddy/core/domain/TaskContentUpdate.java +++ b/core/src/main/java/com/taskbuddy/core/domain/TaskContentUpdate.java @@ -7,6 +7,7 @@ public record TaskContentUpdate( Long userId, String title, String description, + Boolean reminderEnabled, LocalDateTime startDateTime, LocalDateTime endDateTime ) {} diff --git a/core/src/main/java/com/taskbuddy/core/domain/TaskCreate.java b/core/src/main/java/com/taskbuddy/core/domain/TaskCreate.java index 38aedf2..a40f8d2 100644 --- a/core/src/main/java/com/taskbuddy/core/domain/TaskCreate.java +++ b/core/src/main/java/com/taskbuddy/core/domain/TaskCreate.java @@ -6,6 +6,7 @@ public record TaskCreate ( Long userId, String title, String description, + Boolean reminderEnabled, LocalDateTime startDateTime, LocalDateTime endDateTime ) {} diff --git a/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java b/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java index 0139f54..c01e886 100644 --- a/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java +++ b/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java @@ -82,6 +82,7 @@ void setUp() { 1L, "알고리즘 문제 풀기", "백준1902", + false, LocalDateTime.of(2024, 8, 1, 0, 0, 0), LocalDateTime.of(2024, 8, 31, 23, 59, 59)); @@ -150,6 +151,7 @@ void setUp() { 1L, "알고리즘 문제 풀기", "백준4300", + true, LocalDateTime.of(2024, 9, 1, 0, 0, 0), LocalDateTime.of(2024, 9, 10, 23, 59, 59)); From 091034ff30eaa5c4ee955c1692087c4702774cf7 Mon Sep 17 00:00:00 2001 From: seulki Date: Mon, 7 Oct 2024 13:34:55 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor:=20Task=EC=97=90=20reminderEnabled?= =?UTF-8?q?=20=EC=86=8D=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/java/com/taskbuddy/core/service/TaskServiceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java b/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java index c01e886..6813fb2 100644 --- a/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java +++ b/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java @@ -118,6 +118,7 @@ void setUp() { 1L, "알고리즘 문제 풀기", "백준4300", + true, LocalDateTime.of(2024, 9, 1, 0, 0, 0), LocalDateTime.of(2024, 9, 10, 23, 59, 59)); From 9de7ecf16c174029247f77f6abd4489b3d862f5c Mon Sep 17 00:00:00 2001 From: seulki Date: Mon, 7 Oct 2024 14:55:15 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20ReminderSettingsService=20CRUD=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 --- .../api/controller/TaskController.java | 4 ++ .../core/domain/TaskContentUpdate.java | 2 + .../com/taskbuddy/core/domain/TaskCreate.java | 2 + .../core/service/ReminderSettingsService.java | 61 +++++++++++++++++++ .../taskbuddy/core/service/TaskService.java | 15 ++++- .../com/taskbuddy/core/domain/TaskTest.java | 5 ++ .../core/service/TaskServiceTest.java | 17 +++++- 7 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java diff --git a/api/src/main/java/com/taskbuddy/api/controller/TaskController.java b/api/src/main/java/com/taskbuddy/api/controller/TaskController.java index bbaaf8c..9fd64a2 100644 --- a/api/src/main/java/com/taskbuddy/api/controller/TaskController.java +++ b/api/src/main/java/com/taskbuddy/api/controller/TaskController.java @@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.*; import java.net.URI; +import java.time.Duration; @RequiredArgsConstructor @RequestMapping("/v1/tasks") @@ -43,6 +44,8 @@ ResponseEntity> createTask(@RequestBody TaskCreateRequest request dummyUserId, request.title(), request.description(), + true, + Duration.ofMinutes(10), request.timeFrame().startDateTime(), request.timeFrame().endDateTime() ); @@ -66,6 +69,7 @@ ResponseEntity> updateTaskContent(@PathVariable("id") Long id, @R dummyUserId, request.title(), request.description(), + true, request.timeFrame().startDateTime(), request.timeFrame().endDateTime()); taskService.updateContent(taskContentUpdate); diff --git a/core/src/main/java/com/taskbuddy/core/domain/TaskContentUpdate.java b/core/src/main/java/com/taskbuddy/core/domain/TaskContentUpdate.java index cff1f4b..8a20345 100644 --- a/core/src/main/java/com/taskbuddy/core/domain/TaskContentUpdate.java +++ b/core/src/main/java/com/taskbuddy/core/domain/TaskContentUpdate.java @@ -1,5 +1,6 @@ package com.taskbuddy.core.domain; +import java.time.Duration; import java.time.LocalDateTime; public record TaskContentUpdate( @@ -8,6 +9,7 @@ public record TaskContentUpdate( String title, String description, Boolean reminderEnabled, + Duration reminderInterval, LocalDateTime startDateTime, LocalDateTime endDateTime ) {} diff --git a/core/src/main/java/com/taskbuddy/core/domain/TaskCreate.java b/core/src/main/java/com/taskbuddy/core/domain/TaskCreate.java index a40f8d2..05f3b9c 100644 --- a/core/src/main/java/com/taskbuddy/core/domain/TaskCreate.java +++ b/core/src/main/java/com/taskbuddy/core/domain/TaskCreate.java @@ -1,5 +1,6 @@ package com.taskbuddy.core.domain; +import java.time.Duration; import java.time.LocalDateTime; public record TaskCreate ( @@ -7,6 +8,7 @@ public record TaskCreate ( String title, String description, Boolean reminderEnabled, + Duration reminderInterval, LocalDateTime startDateTime, LocalDateTime endDateTime ) {} diff --git a/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java b/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java new file mode 100644 index 0000000..2fd19a5 --- /dev/null +++ b/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java @@ -0,0 +1,61 @@ +package com.taskbuddy.core.service; + +import com.taskbuddy.core.database.repository.ReminderSettingsRepository; +import com.taskbuddy.core.domain.ReminderSettings; +import com.taskbuddy.core.domain.Task; +import com.taskbuddy.core.service.port.ClockHolder; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.Optional; + +@RequiredArgsConstructor +@Service +public class ReminderSettingsService { + private final ReminderSettingsRepository reminderSettingsRepository; + private final ClockHolder clockHolder; + + public ReminderSettings getByTaskId(Long taskId) { + return reminderSettingsRepository.findByTaskId(taskId) + .orElseThrow(() -> new IllegalArgumentException("Task Settings with given task id does not exist.")); + } + + public void initialize(Task task, Duration reminderInterval) { + if (!task.isReminderEnabled()) { + return; + } + + ReminderSettings reminderSettings = ReminderSettings.from(task, reminderInterval); + reminderSettingsRepository.save(reminderSettings); + } + + public void update(Task task, Duration reminderInterval) { + Optional optionalReminderSettings = reminderSettingsRepository.findByTaskId(task.getId()); + + if (optionalReminderSettings.isEmpty()) { + initialize(task, reminderInterval); + return; + } + + ReminderSettings reminderSettings = optionalReminderSettings.get(); + + if (!task.isReminderEnabled()) { + reminderSettingsRepository.deleteById(reminderSettings.getId()); + } else { + reminderSettings.updateReminderInterval(reminderInterval, clockHolder); + reminderSettingsRepository.save(reminderSettings); + } + } + + public void updateLastSentTime(ReminderSettings reminderSettings, LocalDateTime lastSentTime) { + reminderSettings.updateLastReminderSentTime(lastSentTime, clockHolder); + } + + public void deleteByTaskId(Long taskId) { + reminderSettingsRepository.findByTaskId(taskId) + .ifPresent(reminderSettings -> reminderSettingsRepository.deleteById(reminderSettings.getId())); + + } +} diff --git a/core/src/main/java/com/taskbuddy/core/service/TaskService.java b/core/src/main/java/com/taskbuddy/core/service/TaskService.java index e5d5a57..e593f59 100644 --- a/core/src/main/java/com/taskbuddy/core/service/TaskService.java +++ b/core/src/main/java/com/taskbuddy/core/service/TaskService.java @@ -8,11 +8,13 @@ import com.taskbuddy.core.service.port.TaskRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor @Service public class TaskService { private final TaskRepository taskRepository; + private final ReminderSettingsService reminderSettingsService; private final ClockHolder clockHolder; public Task getTask(Long id) { @@ -20,19 +22,25 @@ public Task getTask(Long id) { .orElseThrow(() -> new IllegalArgumentException("The given task with id does not exist.")); } + @Transactional public Long createTask(TaskCreate taskCreate) { - final Task task = Task.from(taskCreate, clockHolder); - final Task savedTask = taskRepository.save(task); + Task task = Task.from(taskCreate, clockHolder); + task = taskRepository.save(task); - return savedTask.getId(); + reminderSettingsService.initialize(task, taskCreate.reminderInterval()); + + return task.getId(); } + @Transactional public void updateContent(TaskContentUpdate taskContentUpdate) { Task task = taskRepository.findById(taskContentUpdate.id()) .orElseThrow(() -> new IllegalArgumentException("The given task with id does not exist.")); task.update(taskContentUpdate, clockHolder); taskRepository.save(task); + + reminderSettingsService.update(task, taskContentUpdate.reminderInterval()); } public void updateDone(TaskDoneUpdate taskDoneUpdate) { @@ -51,5 +59,6 @@ public void deleteTask(Long id) { } taskRepository.deleteById(id); + reminderSettingsService.deleteByTaskId(id); } } diff --git a/core/src/test/java/com/taskbuddy/core/domain/TaskTest.java b/core/src/test/java/com/taskbuddy/core/domain/TaskTest.java index 7c7b73e..a377f79 100644 --- a/core/src/test/java/com/taskbuddy/core/domain/TaskTest.java +++ b/core/src/test/java/com/taskbuddy/core/domain/TaskTest.java @@ -3,6 +3,7 @@ import com.taskbuddy.core.mock.TestClockHolder; import org.junit.jupiter.api.Test; +import java.time.Duration; import java.time.LocalDateTime; import static org.assertj.core.api.Assertions.assertThat; @@ -19,6 +20,8 @@ class TaskTest { 1L, "알고리즘 풀기", "백준1902", + true, + Duration.ofMinutes(10), LocalDateTime.of(2024, 8, 1, 0, 0, 0), LocalDateTime.of(2024, 8, 31, 23, 59, 59)); @@ -64,6 +67,8 @@ class TaskTest { 1L, "알고리즘 풀기", "백준2630", + true, + Duration.ofMinutes(10), LocalDateTime.of(2024, 9, 1, 0, 0, 0), LocalDateTime.of(2024, 9, 30, 23, 59, 59)); diff --git a/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java b/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java index 6813fb2..9208b8d 100644 --- a/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java +++ b/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.time.Duration; import java.time.LocalDateTime; import java.util.Optional; @@ -20,15 +21,16 @@ class TaskServiceTest { private TaskService taskService; private TaskRepository taskRepository; - + private ReminderSettingsService reminderSettingsService; private LocalDateTime currentDateTime; @BeforeEach void setUp() { taskRepository = Mockito.mock(TaskRepository.class); + reminderSettingsService = Mockito.mock(ReminderSettingsService.class); currentDateTime = LocalDateTime.now(); - taskService = new TaskService(taskRepository, new TestClockHolder(currentDateTime)); + taskService = new TaskService(taskRepository, reminderSettingsService, new TestClockHolder(currentDateTime)); } @Test @@ -83,6 +85,7 @@ void setUp() { "알고리즘 문제 풀기", "백준1902", false, + null, LocalDateTime.of(2024, 8, 1, 0, 0, 0), LocalDateTime.of(2024, 8, 31, 23, 59, 59)); @@ -99,6 +102,7 @@ void setUp() { .updatedAt(LocalDateTime.now()) .build(); Mockito.when(taskRepository.save(Mockito.any())).thenReturn(mockTask); + Mockito.doNothing().when(reminderSettingsService).initialize(Mockito.any(), Mockito.any()); //when Long result = taskService.createTask(taskCreate); @@ -107,6 +111,7 @@ void setUp() { assertThat(result).isNotNull(); assertThat(result).isGreaterThan(0); Mockito.verify(taskRepository, Mockito.times(1)).save(Mockito.any(Task.class)); + Mockito.verify(reminderSettingsService, Mockito.times(1)).initialize(Mockito.any(Task.class), Mockito.any()); } @Test @@ -119,6 +124,7 @@ void setUp() { "알고리즘 문제 풀기", "백준4300", true, + Duration.ofMinutes(10), LocalDateTime.of(2024, 9, 1, 0, 0, 0), LocalDateTime.of(2024, 9, 10, 23, 59, 59)); @@ -127,6 +133,7 @@ void setUp() { .isInstanceOf(IllegalArgumentException.class) .hasMessage("The given task with id does not exist."); Mockito.verify(taskRepository, Mockito.never()).save(Mockito.any(Task.class)); + } @Test @@ -146,6 +153,7 @@ void setUp() { .createdAt(givenCreatedDateTime) .build(); Mockito.when(taskRepository.findById(givenId)).thenReturn(Optional.of(mockTask)); + Mockito.doNothing().when(reminderSettingsService).initialize(Mockito.any(), Mockito.any()); TaskContentUpdate taskContentUpdate = new TaskContentUpdate( givenId, @@ -153,6 +161,7 @@ void setUp() { "알고리즘 문제 풀기", "백준4300", true, + Duration.ofMinutes(10), LocalDateTime.of(2024, 9, 1, 0, 0, 0), LocalDateTime.of(2024, 9, 10, 23, 59, 59)); @@ -171,6 +180,7 @@ void setUp() { assertThat(findTask.getCreatedAt()).isEqualTo(givenCreatedDateTime); assertThat(findTask.getUpdatedAt()).isEqualTo(currentDateTime); Mockito.verify(taskRepository, Mockito.times(1)).save(Mockito.any(Task.class)); + Mockito.verify(reminderSettingsService, Mockito.times(1)).update(Mockito.any(Task.class), Mockito.any()); } @Test @@ -184,6 +194,7 @@ void setUp() { .isInstanceOf(IllegalArgumentException.class) .hasMessage("The given task with id does not exist."); Mockito.verify(taskRepository, Mockito.never()).deleteById(givenId); + Mockito.verify(reminderSettingsService, Mockito.never()).deleteByTaskId(givenId); } @Test @@ -191,11 +202,13 @@ void setUp() { //given Long givenId = 1L; Mockito.when(taskRepository.existsById(givenId)).thenReturn(true); + Mockito.doNothing().when(reminderSettingsService).deleteByTaskId(givenId); //when Assertions.assertDoesNotThrow(() -> taskService.deleteTask(givenId)); //then Mockito.verify(taskRepository, Mockito.times(1)).deleteById(givenId); + Mockito.verify(reminderSettingsService, Mockito.times(1)).deleteByTaskId(givenId); } } From ee4a2543142ed60f7717fd071bcb59e201cf0fa1 Mon Sep 17 00:00:00 2001 From: seulki Date: Mon, 7 Oct 2024 14:56:42 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=20Task=20delete=20=EC=97=90=20Tra?= =?UTF-8?q?nsactional=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/main/java/com/taskbuddy/core/service/TaskService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/com/taskbuddy/core/service/TaskService.java b/core/src/main/java/com/taskbuddy/core/service/TaskService.java index e593f59..f5d4b37 100644 --- a/core/src/main/java/com/taskbuddy/core/service/TaskService.java +++ b/core/src/main/java/com/taskbuddy/core/service/TaskService.java @@ -43,6 +43,7 @@ public void updateContent(TaskContentUpdate taskContentUpdate) { reminderSettingsService.update(task, taskContentUpdate.reminderInterval()); } + public void updateDone(TaskDoneUpdate taskDoneUpdate) { Task task = taskRepository.findById(taskDoneUpdate.id()) .orElseThrow(() -> new IllegalArgumentException("The given task with id does not exist.")); @@ -51,6 +52,7 @@ public void updateDone(TaskDoneUpdate taskDoneUpdate) { taskRepository.save(task); } + @Transactional public void deleteTask(Long id) { final boolean exists = taskRepository.existsById(id); From d601ded7f02851576eb5615c7d64afdb6da9a463 Mon Sep 17 00:00:00 2001 From: seulki Date: Mon, 7 Oct 2024 16:41:25 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=20ReminderSettings=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/TaskController.java | 1 + .../DefaultReminderSettingsRepository.java | 26 +++ .../ReminderSettingsRepository.java | 14 ++ .../core/domain/ReminderSettings.java | 66 ++++++++ .../core/service/ReminderSettingsService.java | 4 +- .../core/domain/ReminderSettingsTest.java | 154 ++++++++++++++++++ .../service/ReminderSettingsServiceTest.java | 117 +++++++++++++ .../core/service/TaskServiceTest.java | 2 +- 8 files changed, 381 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/com/taskbuddy/core/database/repository/DefaultReminderSettingsRepository.java create mode 100644 core/src/main/java/com/taskbuddy/core/database/repository/ReminderSettingsRepository.java create mode 100644 core/src/main/java/com/taskbuddy/core/domain/ReminderSettings.java create mode 100644 core/src/test/java/com/taskbuddy/core/domain/ReminderSettingsTest.java create mode 100644 core/src/test/java/com/taskbuddy/core/service/ReminderSettingsServiceTest.java diff --git a/api/src/main/java/com/taskbuddy/api/controller/TaskController.java b/api/src/main/java/com/taskbuddy/api/controller/TaskController.java index 9fd64a2..e4d81a2 100644 --- a/api/src/main/java/com/taskbuddy/api/controller/TaskController.java +++ b/api/src/main/java/com/taskbuddy/api/controller/TaskController.java @@ -70,6 +70,7 @@ ResponseEntity> updateTaskContent(@PathVariable("id") Long id, @R request.title(), request.description(), true, + Duration.ofMinutes(10), request.timeFrame().startDateTime(), request.timeFrame().endDateTime()); taskService.updateContent(taskContentUpdate); diff --git a/core/src/main/java/com/taskbuddy/core/database/repository/DefaultReminderSettingsRepository.java b/core/src/main/java/com/taskbuddy/core/database/repository/DefaultReminderSettingsRepository.java new file mode 100644 index 0000000..4ba3da7 --- /dev/null +++ b/core/src/main/java/com/taskbuddy/core/database/repository/DefaultReminderSettingsRepository.java @@ -0,0 +1,26 @@ +package com.taskbuddy.core.database.repository; + +import com.taskbuddy.core.domain.ReminderSettings; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +//임시생성 +@Repository +public class DefaultReminderSettingsRepository implements ReminderSettingsRepository { + + @Override + public Optional findByTaskId(Long taskId) { + return Optional.empty(); + } + + @Override + public void save(ReminderSettings reminderSettings) { + + } + + @Override + public void deleteById(Long id) { + + } +} diff --git a/core/src/main/java/com/taskbuddy/core/database/repository/ReminderSettingsRepository.java b/core/src/main/java/com/taskbuddy/core/database/repository/ReminderSettingsRepository.java new file mode 100644 index 0000000..eb3fc4d --- /dev/null +++ b/core/src/main/java/com/taskbuddy/core/database/repository/ReminderSettingsRepository.java @@ -0,0 +1,14 @@ +package com.taskbuddy.core.database.repository; + +import com.taskbuddy.core.domain.ReminderSettings; + +import java.util.Optional; + +public interface ReminderSettingsRepository { + + Optional findByTaskId(Long taskId); + + void save(ReminderSettings reminderSettings); + + void deleteById(Long id); +} diff --git a/core/src/main/java/com/taskbuddy/core/domain/ReminderSettings.java b/core/src/main/java/com/taskbuddy/core/domain/ReminderSettings.java new file mode 100644 index 0000000..ccfa500 --- /dev/null +++ b/core/src/main/java/com/taskbuddy/core/domain/ReminderSettings.java @@ -0,0 +1,66 @@ +package com.taskbuddy.core.domain; + +import com.taskbuddy.core.service.port.ClockHolder; +import lombok.Builder; +import lombok.Getter; + +import java.time.Duration; +import java.time.LocalDateTime; + +@Getter +public class ReminderSettings { + private final Long id; + private final Task task; + private LocalDateTime lastReminderSentTime; + private Duration reminderInterval; + private final LocalDateTime createdAt; + private LocalDateTime updatedAt; + + @Builder + public ReminderSettings(Long id, Task task, LocalDateTime lastReminderSentTime, Duration reminderInterval, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.id = id; + this.task = task; + this.lastReminderSentTime = lastReminderSentTime; + this.reminderInterval = reminderInterval; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public static ReminderSettings from(Task task, Duration reminderInterval, ClockHolder clockHolder) { + final LocalDateTime currentDateTime = clockHolder.currentDateTime(); + + return ReminderSettings.builder() + .task(task) + .reminderInterval(reminderInterval) + .createdAt(currentDateTime) + .updatedAt(currentDateTime) + .build(); + } + + public void updateLastReminderSentTime(LocalDateTime lastReminderSentTime, ClockHolder clockHolder) { + this.lastReminderSentTime = lastReminderSentTime; + this.updatedAt = clockHolder.currentDateTime(); + } + + public boolean isReminderDue(ClockHolder clockHolder) { + LocalDateTime currentDateTime = clockHolder.currentDateTime(); + LocalDateTime taskStartDateTime = task.getTimeFrame().startDateTime(); + + if (currentDateTime.isBefore(taskStartDateTime)) { + return false; + } + + Duration timeSinceStart = Duration.between(taskStartDateTime, currentDateTime); + + return timeSinceStart.toMinutes() % reminderInterval.toMinutes() == 0; + } + + public void updateReminderInterval(Duration reminderInterval, ClockHolder clockHolder) { + this.reminderInterval = reminderInterval; + this.updatedAt = clockHolder.currentDateTime(); + } + + public Long getTaskId() { + return task.getId(); + } +} diff --git a/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java b/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java index 2fd19a5..07d113d 100644 --- a/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java +++ b/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java @@ -22,12 +22,13 @@ public ReminderSettings getByTaskId(Long taskId) { .orElseThrow(() -> new IllegalArgumentException("Task Settings with given task id does not exist.")); } + public void initialize(Task task, Duration reminderInterval) { if (!task.isReminderEnabled()) { return; } - ReminderSettings reminderSettings = ReminderSettings.from(task, reminderInterval); + ReminderSettings reminderSettings = ReminderSettings.from(task, reminderInterval, clockHolder); reminderSettingsRepository.save(reminderSettings); } @@ -56,6 +57,5 @@ public void updateLastSentTime(ReminderSettings reminderSettings, LocalDateTime public void deleteByTaskId(Long taskId) { reminderSettingsRepository.findByTaskId(taskId) .ifPresent(reminderSettings -> reminderSettingsRepository.deleteById(reminderSettings.getId())); - } } diff --git a/core/src/test/java/com/taskbuddy/core/domain/ReminderSettingsTest.java b/core/src/test/java/com/taskbuddy/core/domain/ReminderSettingsTest.java new file mode 100644 index 0000000..25161a1 --- /dev/null +++ b/core/src/test/java/com/taskbuddy/core/domain/ReminderSettingsTest.java @@ -0,0 +1,154 @@ +package com.taskbuddy.core.domain; + +import com.taskbuddy.core.mock.TestClockHolder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +class ReminderSettingsTest { + + @Test + void task와_reminderInterval로_ReminderSettings_객체를_생성할_수_있다() { + //given + Task mockTask = Mockito.mock(Task.class); + Mockito.when(mockTask.getId()).thenReturn(1L); + + Duration givenReminderInterval = Duration.ofMinutes(10); + + LocalDateTime createdDateTime = LocalDateTime.now(); + TestClockHolder testClockHolder = new TestClockHolder(createdDateTime); + + //when + ReminderSettings reminderSettings = ReminderSettings.from(mockTask, givenReminderInterval, testClockHolder); + + //then + assertThat(reminderSettings).isNotNull(); + assertThat(reminderSettings.getId()).isNull(); + assertThat(reminderSettings.getTaskId()).isEqualTo(1L); + assertThat(reminderSettings.getReminderInterval()).isEqualTo(givenReminderInterval); + assertThat(reminderSettings.getLastReminderSentTime()).isNull();; + assertThat(reminderSettings.getCreatedAt()).isEqualTo(createdDateTime); + assertThat(reminderSettings.getUpdatedAt()).isEqualTo(createdDateTime); + } + + @Test + void 최근발송일시를_업데이트할_수_있다() { + //given + LocalDateTime createdDateTime = LocalDateTime.now().minusDays(3); + LocalDateTime lastReminderSentTime = LocalDateTime.now().minusMinutes(20); + Duration reminderInterval = Duration.ofMinutes(20); + + ReminderSettings reminderSettings = ReminderSettings.builder() + .id(1L) + .task(Task.builder().id(1L).build()) + .lastReminderSentTime(lastReminderSentTime) + .reminderInterval(reminderInterval) + .createdAt(createdDateTime) + .updatedAt(createdDateTime) + .build(); + + LocalDateTime updatedLastSentTime = LocalDateTime.now(); + LocalDateTime updatedDateTime = LocalDateTime.now(); + + //when + reminderSettings.updateLastReminderSentTime(updatedLastSentTime, new TestClockHolder(updatedDateTime)); + + //then + assertThat(reminderSettings.getId()).isEqualTo(1L); + assertThat(reminderSettings.getTaskId()).isEqualTo(1L); + assertThat(reminderSettings.getReminderInterval()).isEqualTo(reminderInterval); + assertThat(reminderSettings.getLastReminderSentTime()).isEqualTo(updatedLastSentTime); + assertThat(reminderSettings.getCreatedAt()).isEqualTo(createdDateTime); + assertThat(reminderSettings.getUpdatedAt()).isEqualTo(updatedDateTime); + } + + @Test + void 현재일시가_Reminder_발송일시인지_여부를_반환한다() { + //given + LocalDateTime createdDateTime = LocalDateTime.now().minusDays(3); + LocalDateTime taskStartDateTime = LocalDate.now().atStartOfDay(); + Task task = Task.builder() + .id(1L) + .reminderEnabled(true) + .timeFrame(new TimeFrame(taskStartDateTime, LocalDate.now().plusWeeks(1).atStartOfDay())) + .createdAt(createdDateTime) + .updatedAt(createdDateTime) + .build(); + + LocalDateTime lastReminderSentTime = LocalDateTime.now().minusMinutes(20); + Duration reminderInterval = Duration.ofMinutes(10); + ReminderSettings reminderSettings = ReminderSettings.builder() + .id(1L) + .task(task) + .lastReminderSentTime(lastReminderSentTime) + .reminderInterval(reminderInterval) + .createdAt(createdDateTime) + .updatedAt(createdDateTime) + .build(); + + //when & then + Assertions.assertAll( + () -> { + LocalDateTime currentDateTime = taskStartDateTime; + Assertions.assertTrue(reminderSettings.isReminderDue(new TestClockHolder(currentDateTime))); + }, + () -> { + LocalDateTime currentDateTime = taskStartDateTime.plusMinutes(10); + Assertions.assertTrue(reminderSettings.isReminderDue(new TestClockHolder(currentDateTime))); + }, + () -> { + LocalDateTime currentDateTime = taskStartDateTime.plusMinutes(20); + Assertions.assertTrue(reminderSettings.isReminderDue(new TestClockHolder(currentDateTime))); + }, + () -> { + LocalDateTime currentDateTime = taskStartDateTime.plusMinutes(30); + Assertions.assertTrue(reminderSettings.isReminderDue(new TestClockHolder(currentDateTime))); + }, + () -> { + LocalDateTime currentDateTime = taskStartDateTime.plusMinutes(3); + Assertions.assertFalse(reminderSettings.isReminderDue(new TestClockHolder(currentDateTime))); + }, + () -> { + LocalDateTime currentDateTime = taskStartDateTime.plusMinutes(22); + Assertions.assertFalse(reminderSettings.isReminderDue(new TestClockHolder(currentDateTime))); + } + ); + } + + @Test + void ReminderInterval을_업데이트할_수_있다() { + //given + LocalDateTime createdDateTime = LocalDateTime.now().minusDays(3); + LocalDateTime lastReminderSentTime = LocalDateTime.now().minusMinutes(20); + Duration reminderInterval = Duration.ofMinutes(20); + + ReminderSettings reminderSettings = ReminderSettings.builder() + .id(1L) + .task(Task.builder().id(1L).build()) + .lastReminderSentTime(lastReminderSentTime) + .reminderInterval(reminderInterval) + .createdAt(createdDateTime) + .updatedAt(createdDateTime) + .build(); + + Duration updatedReminderInterval = Duration.ofHours(1); + LocalDateTime updatedDateTime = LocalDateTime.now(); + + //when + reminderSettings.updateReminderInterval(updatedReminderInterval, new TestClockHolder(updatedDateTime)); + + //then + assertThat(reminderSettings.getId()).isEqualTo(1L); + assertThat(reminderSettings.getTaskId()).isEqualTo(1L); + assertThat(reminderSettings.getReminderInterval()).isEqualTo(updatedReminderInterval); + assertThat(reminderSettings.getLastReminderSentTime()).isEqualTo(lastReminderSentTime); + assertThat(reminderSettings.getCreatedAt()).isEqualTo(createdDateTime); + assertThat(reminderSettings.getUpdatedAt()).isEqualTo(updatedDateTime); + } +} diff --git a/core/src/test/java/com/taskbuddy/core/service/ReminderSettingsServiceTest.java b/core/src/test/java/com/taskbuddy/core/service/ReminderSettingsServiceTest.java new file mode 100644 index 0000000..d583bec --- /dev/null +++ b/core/src/test/java/com/taskbuddy/core/service/ReminderSettingsServiceTest.java @@ -0,0 +1,117 @@ +package com.taskbuddy.core.service; + +import com.taskbuddy.core.database.repository.ReminderSettingsRepository; +import com.taskbuddy.core.domain.ReminderSettings; +import com.taskbuddy.core.domain.Task; +import com.taskbuddy.core.mock.TestClockHolder; +import com.taskbuddy.core.service.port.ClockHolder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.Optional; + +import static org.mockito.Mockito.*; + +class ReminderSettingsServiceTest { + private ReminderSettingsService reminderSettingsService; + private ReminderSettingsRepository reminderSettingsRepository; + private ClockHolder clockHolder; + + @BeforeEach + void setUp() { + reminderSettingsRepository = mock(ReminderSettingsRepository.class); + clockHolder = new TestClockHolder(LocalDateTime.now()); + + reminderSettingsService = new ReminderSettingsService(reminderSettingsRepository, clockHolder); + } + + @Test + void Task의_ReminderEnabled가_false라면_초기화를_하지_않고_종료한다() { + //given + Task mockTask = mock(Task.class); + when(mockTask.isReminderEnabled()).thenReturn(false); + + //when + reminderSettingsService.initialize(mockTask, null); + + //then + verify(reminderSettingsRepository, never()).save(any(ReminderSettings.class)); + } + + @Test + void Task의_ReminderEnabled가_true라면_주어진_interval설정으로_초기화된다() { + //given + Task mockTask = mock(Task.class); + when(mockTask.isReminderEnabled()).thenReturn(true); + + Duration givenReminderInterval = Duration.ofMinutes(10); + + //when + reminderSettingsService.initialize(mockTask, givenReminderInterval); + + //then + verify(reminderSettingsRepository, times(1)).save(any(ReminderSettings.class)); + } + + @Test + void 주어진_TaskId로_ReminderSettings가_존재하지_않는경우_새로_초기화한다() { + //given + Task mockTask = mock(Task.class); + when(mockTask.getId()).thenReturn(1L); + when(reminderSettingsRepository.findByTaskId(mockTask.getId())).thenReturn(Optional.empty()); + + Duration givenReminderInterval = Duration.ofMinutes(10); + + ReminderSettingsService spyReminderSettingsService = spy(this.reminderSettingsService); + + //when + spyReminderSettingsService.update(mockTask, givenReminderInterval); + + //then + verify(spyReminderSettingsService, times(1)).initialize(mockTask, givenReminderInterval); + verify(reminderSettingsRepository, never()).save(any(ReminderSettings.class)); + verify(reminderSettingsRepository, never()).deleteById(anyLong()); + } + + @Test + void 주어진_TaskId로_ReminderSettings가_존재하는데_Task의_reminder설정이_false일_경우_ReminderSettings를_삭제한다() { + //given + Task mockTask = mock(Task.class); + when(mockTask.getId()).thenReturn(1L); + when(mockTask.isReminderEnabled()).thenReturn(false); + + ReminderSettings mockReminderSettings = mock(ReminderSettings.class); + when(reminderSettingsRepository.findByTaskId(mockTask.getId())).thenReturn(Optional.of(mockReminderSettings)); + + Duration givenReminderInterval = Duration.ofMinutes(10); + + //when + reminderSettingsService.update(mockTask, givenReminderInterval); + + //then + verify(reminderSettingsRepository, times(1)).deleteById(mockReminderSettings.getId()); + verify(reminderSettingsRepository, never()).save(any(ReminderSettings.class)); + } + + @Test + void 주어진_TaskId로_ReminderSettings가_존재하면서_Task의_reminder설정이_true일_경우_ReminderInterval을_업데이트한다() { + //given + Task mockTask = mock(Task.class); + when(mockTask.getId()).thenReturn(1L); + when(mockTask.isReminderEnabled()).thenReturn(true); + + ReminderSettings mockReminderSettings = mock(ReminderSettings.class); + when(reminderSettingsRepository.findByTaskId(mockTask.getId())).thenReturn(Optional.of(mockReminderSettings)); + + Duration givenReminderInterval = Duration.ofMinutes(10); + + //when + reminderSettingsService.update(mockTask, givenReminderInterval); + + //then + verify(mockReminderSettings, times(1)).updateReminderInterval(givenReminderInterval, clockHolder); + verify(reminderSettingsRepository, times(1)).save(mockReminderSettings); + } +} diff --git a/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java b/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java index 9208b8d..365d71a 100644 --- a/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java +++ b/core/src/test/java/com/taskbuddy/core/service/TaskServiceTest.java @@ -133,7 +133,7 @@ void setUp() { .isInstanceOf(IllegalArgumentException.class) .hasMessage("The given task with id does not exist."); Mockito.verify(taskRepository, Mockito.never()).save(Mockito.any(Task.class)); - + Mockito.verify(reminderSettingsService, Mockito.never()).initialize(Mockito.any(Task.class), Mockito.any()); } @Test From c5fc51c7b23b174647040bb61af8a5143b2322e9 Mon Sep 17 00:00:00 2001 From: seulki Date: Mon, 7 Oct 2024 16:41:50 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor:=20UserService=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/taskbuddy/core/domain/User.java | 12 +++++++++++- .../com/taskbuddy/core/service/UserService.java | 13 +++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/com/taskbuddy/core/service/UserService.java diff --git a/core/src/main/java/com/taskbuddy/core/domain/User.java b/core/src/main/java/com/taskbuddy/core/domain/User.java index c45c34c..ca616a2 100644 --- a/core/src/main/java/com/taskbuddy/core/domain/User.java +++ b/core/src/main/java/com/taskbuddy/core/domain/User.java @@ -1,4 +1,14 @@ package com.taskbuddy.core.domain; -public record User(Long id) { +import lombok.Getter; + +import java.time.LocalDateTime; + +@Getter +public class User { + private Long id; + private boolean loggedIn; + private boolean reminderEnabled; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; } diff --git a/core/src/main/java/com/taskbuddy/core/service/UserService.java b/core/src/main/java/com/taskbuddy/core/service/UserService.java new file mode 100644 index 0000000..8cb761f --- /dev/null +++ b/core/src/main/java/com/taskbuddy/core/service/UserService.java @@ -0,0 +1,13 @@ +package com.taskbuddy.core.service; + +import com.taskbuddy.core.domain.User; +import org.springframework.stereotype.Service; + +@Service +public class UserService { + + //임시 구현 + public boolean isUserLoggedIn(User user) { + return user.isLoggedIn(); + } +} From 14b59f07e1946039c77729e9eef1bd8e27d2020e Mon Sep 17 00:00:00 2001 From: seulki Date: Mon, 7 Oct 2024 18:05:51 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=20ReminderNotificationService=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ReminderNotificationService.java | 48 +++++++++++++++++++ .../core/service/ReminderSettingsService.java | 1 - 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/com/taskbuddy/core/service/ReminderNotificationService.java diff --git a/core/src/main/java/com/taskbuddy/core/service/ReminderNotificationService.java b/core/src/main/java/com/taskbuddy/core/service/ReminderNotificationService.java new file mode 100644 index 0000000..7a0a857 --- /dev/null +++ b/core/src/main/java/com/taskbuddy/core/service/ReminderNotificationService.java @@ -0,0 +1,48 @@ +package com.taskbuddy.core.service; + +import com.taskbuddy.core.domain.ReminderSettings; +import com.taskbuddy.core.domain.Task; +import com.taskbuddy.core.domain.User; +import com.taskbuddy.core.service.port.ClockHolder; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +@RequiredArgsConstructor +@Service +public class ReminderNotificationService { + private final ReminderSettingsService reminderSettingsService; + private final UserService userService; +// private final NotificationService notificationService; + private final ClockHolder clockHolder; + + public void sendNotification(Task task) { + User user = task.getUser(); + + // 1. 유저가 리마인드 알림설정이 켜져있는지 확인 + if (!user.isReminderEnabled()) { + return; // 유저가 알림을 원하지 않으면 스킵 + } + + // 2. Task의 리마인드 설정이 켜져 있는지 확인 + if (!task.isReminderEnabled()) { + return; // Task의 리마인드 설정이 꺼져 있으면 스킵 + } + + // 3. 리마인더주기에 맞는지 확인 + ReminderSettings reminderSettings = reminderSettingsService.getByTaskId(task.getId()); + + // 마지막으로 알림을 보낼 시간이 리마인드 주기 이상일 경우에만 알림 전송 + if (!reminderSettings.isReminderDue(clockHolder)) { + return; // 아직 리마인드 주기가 지나지 않았으므로 스킵 + } + + // 4. 유저가 현재 접속 중인지 확인 (접속 중이 아니면 리마인드) + if (!userService.isUserLoggedIn(user)) { + //리마인더 알림 전송 +// notificationService.sendReminder(user, task); + reminderSettingsService.updateLastSentTime(reminderSettings, LocalDateTime.now()); + } + } +} diff --git a/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java b/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java index 07d113d..cfe8322 100644 --- a/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java +++ b/core/src/main/java/com/taskbuddy/core/service/ReminderSettingsService.java @@ -22,7 +22,6 @@ public ReminderSettings getByTaskId(Long taskId) { .orElseThrow(() -> new IllegalArgumentException("Task Settings with given task id does not exist.")); } - public void initialize(Task task, Duration reminderInterval) { if (!task.isReminderEnabled()) { return;