From f6494aeff190991246ed96154ea1df7f2a764a44 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Wed, 3 Jul 2024 15:37:26 +0200 Subject: [PATCH 01/15] Backend: -Add ReminderScheduler.java -Add NotificationService.java -Add Annotation @EnableScheduling in BackendApplication.java --- .../backend/BackendApplication.java | 2 ++ .../backend/reminder/NotificationService.java | 10 ++++++ .../backend/reminder/Reminder.java | 1 - .../backend/reminder/ReminderScheduler.java | 32 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/com/github/tingshi2015/backend/reminder/NotificationService.java create mode 100644 backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java diff --git a/backend/src/main/java/com/github/tingshi2015/backend/BackendApplication.java b/backend/src/main/java/com/github/tingshi2015/backend/BackendApplication.java index 2c6a366..6ab8198 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/BackendApplication.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/BackendApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication +@EnableScheduling public class BackendApplication { public static void main(String[] args) { diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/NotificationService.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/NotificationService.java new file mode 100644 index 0000000..5cc3176 --- /dev/null +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/NotificationService.java @@ -0,0 +1,10 @@ +package com.github.tingshi2015.backend.reminder; + +import org.springframework.stereotype.Service; + +@Service +public class NotificationService { + public void sendNotification(Reminder reminder){ + System.out.println("Reminder Alert: " + reminder.name() + " at " + reminder.time() + ", " + reminder.date()); + } +} diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/Reminder.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/Reminder.java index f22dd04..990c0b7 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/Reminder.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/Reminder.java @@ -1,5 +1,4 @@ package com.github.tingshi2015.backend.reminder; - import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java new file mode 100644 index 0000000..d6ebd78 --- /dev/null +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java @@ -0,0 +1,32 @@ +package com.github.tingshi2015.backend.reminder; + +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.management.Notification; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class ReminderScheduler { + private final ReminderRepository reminderRepository; + private final NotificationService notificationService; + + @Scheduled(fixedRate = 60000) //check every 60 seconds + public void checkReminders(){ + List reminders = reminderRepository.findAll(); + LocalDate today = LocalDate.now(); + LocalTime now = LocalTime.now().withSecond(0).withNano(0); //ignore second & Nano-second + + for (Reminder reminder: reminders){ + if (reminder.date().equals(today) && reminder.time().withSecond(0).withNano(0).equals(now)){ + notificationService.sendNotification(reminder); + } + } + + + } +} From 387a268d826d40c3b9799691be6418417967e8d4 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Wed, 3 Jul 2024 15:49:04 +0200 Subject: [PATCH 02/15] Backend: Revise the Bug of "NullPointerException" in ReminderScheduler.java --- .../github/tingshi2015/backend/reminder/ReminderScheduler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java index d6ebd78..17055c8 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java @@ -22,7 +22,8 @@ public void checkReminders(){ LocalTime now = LocalTime.now().withSecond(0).withNano(0); //ignore second & Nano-second for (Reminder reminder: reminders){ - if (reminder.date().equals(today) && reminder.time().withSecond(0).withNano(0).equals(now)){ + if(reminder.date() != null && reminder.time() != null && + reminder.date().equals(today) && reminder.time().withSecond(0).withNano(0).equals(now)){ notificationService.sendNotification(reminder); } } From 43a9361c91e7faec2d2fa4d6e91c116de3df5938 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Wed, 3 Jul 2024 15:55:47 +0200 Subject: [PATCH 03/15] Backend: -Change the for-loop to stream --- .../tingshi2015/backend/reminder/ReminderScheduler.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java index 17055c8..6be2729 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java @@ -21,12 +21,17 @@ public void checkReminders(){ LocalDate today = LocalDate.now(); LocalTime now = LocalTime.now().withSecond(0).withNano(0); //ignore second & Nano-second - for (Reminder reminder: reminders){ +/* for (Reminder reminder: reminders){ if(reminder.date() != null && reminder.time() != null && reminder.date().equals(today) && reminder.time().withSecond(0).withNano(0).equals(now)){ notificationService.sendNotification(reminder); } - } + }*/ + + reminders.stream() + .filter(reminder -> reminder.date() != null && reminder.time() != null) + .filter(reminder -> reminder.date().equals(today) && reminder.time().withSecond(0).withNano(0).equals(now)) + .forEach(notificationService::sendNotification); } From 6419aa1ba542b4105491ce7dff14e2dd2a9df53a Mon Sep 17 00:00:00 2001 From: tingSHI Date: Wed, 3 Jul 2024 16:35:55 +0200 Subject: [PATCH 04/15] Backend: - in ReminderController: Add @GetMapping("/upcoming") - in ReminderService: Add getUpcomingReminders() Method - change the ReminderScheduler --- .../backend/reminder/ReminderController.java | 8 +++++++ .../backend/reminder/ReminderScheduler.java | 21 +++---------------- .../backend/reminder/ReminderService.java | 14 +++++++++++++ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderController.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderController.java index 6d328ba..a909134 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderController.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderController.java @@ -3,6 +3,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.List; @RestController @@ -37,4 +39,10 @@ public Reminder putAReminder(@RequestBody ReminderDTO updateReminder, @PathVaria // return reminderService.getReminderById(id); // } + @GetMapping("/upcoming") + public List getUpcomingReminders(){ + return reminderService.getUpcomingReminders(); + + } + } diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java index 6be2729..2804420 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java @@ -12,27 +12,12 @@ @Component @RequiredArgsConstructor public class ReminderScheduler { - private final ReminderRepository reminderRepository; + private final ReminderService reminderService; private final NotificationService notificationService; @Scheduled(fixedRate = 60000) //check every 60 seconds public void checkReminders(){ - List reminders = reminderRepository.findAll(); - LocalDate today = LocalDate.now(); - LocalTime now = LocalTime.now().withSecond(0).withNano(0); //ignore second & Nano-second - -/* for (Reminder reminder: reminders){ - if(reminder.date() != null && reminder.time() != null && - reminder.date().equals(today) && reminder.time().withSecond(0).withNano(0).equals(now)){ - notificationService.sendNotification(reminder); - } - }*/ - - reminders.stream() - .filter(reminder -> reminder.date() != null && reminder.time() != null) - .filter(reminder -> reminder.date().equals(today) && reminder.time().withSecond(0).withNano(0).equals(now)) - .forEach(notificationService::sendNotification); - - + List upcomingReminders = reminderService.getUpcomingReminders(); + upcomingReminders.forEach(notificationService::sendNotification); } } diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java index e12e1b7..6645ee6 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java @@ -3,8 +3,11 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.List; import java.util.NoSuchElementException; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -46,8 +49,19 @@ public Reminder updateAReminder(ReminderDTO updateReminder, String id) { return reminderRepository.save(reminderToUpdate); } + // public Reminder getReminderById(String id) { // return reminderRepository.findById(id) // .orElseThrow(()-> new NoSuchElementException("Reminder with id: " + id + " not found. Can't getReminderById")); // } + + public List getUpcomingReminders() { + LocalDate today = LocalDate.now(); + LocalTime now = LocalTime.now().withSecond(0).withNano(0); //ignore second & Nano-second + + return reminderRepository.findAll().stream() + .filter(reminder -> reminder.date() != null && reminder.time() != null) + .filter(reminder -> reminder.date().equals(today) && reminder.time().withSecond(0).withNano(0).equals(now)) + .collect(Collectors.toList()); + } } From fff97cd9b115bd6c3a9f80133f0a840a91bd6d33 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Wed, 3 Jul 2024 16:37:15 +0200 Subject: [PATCH 05/15] Backend: - delete unused import --- .../tingshi2015/backend/reminder/ReminderController.java | 2 -- .../github/tingshi2015/backend/reminder/ReminderScheduler.java | 3 --- 2 files changed, 5 deletions(-) diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderController.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderController.java index a909134..dbd1019 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderController.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderController.java @@ -3,8 +3,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import java.time.LocalDate; -import java.time.LocalTime; import java.util.List; @RestController diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java index 2804420..52edcc1 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderScheduler.java @@ -4,9 +4,6 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import javax.management.Notification; -import java.time.LocalDate; -import java.time.LocalTime; import java.util.List; @Component From cde1c400b3e1ec4dfbd0774bb75b0ffd9dec58c8 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Wed, 3 Jul 2024 18:17:17 +0200 Subject: [PATCH 06/15] Frontend: - Add UpcomingReminderGallery.tsx - Add in Homepage --- .../components/UpcomingReminderGallery.tsx | 41 +++++++++++++++++++ frontend/src/page/HomePage.tsx | 2 + 2 files changed, 43 insertions(+) create mode 100644 frontend/src/components/UpcomingReminderGallery.tsx diff --git a/frontend/src/components/UpcomingReminderGallery.tsx b/frontend/src/components/UpcomingReminderGallery.tsx new file mode 100644 index 0000000..f1ed565 --- /dev/null +++ b/frontend/src/components/UpcomingReminderGallery.tsx @@ -0,0 +1,41 @@ +import {useEffect, useState} from "react"; +import {Reminder} from "../types/Reminder.ts"; +import axios from "axios"; + +export default function UpcomingReminderGallery() { + const [upcomingReminders, setUpcomingReminders] = useState([]) + + useEffect(() => { + getUpcomingReminders() + + const interval = setInterval(() => {getUpcomingReminders(); + }, 60000); + + return () => clearInterval(interval); + + }, []); + + + const getUpcomingReminders = () => { + axios.get("api/reminders/upcoming") + .then(response => setUpcomingReminders(response.data)) + .catch(error => console.error("Error getting upcoming reminders", error)) + .finally(() => { + console.log("getUpcomingReminder_successful") + }) + } + + return( +
+

Upcoming Reminders

+
    + {upcomingReminders.map(reminder => ( +
  • + {reminder.name} at {reminder.date} {reminder.time} +
  • + ))} +
+
+ ) + +} diff --git a/frontend/src/page/HomePage.tsx b/frontend/src/page/HomePage.tsx index 33a1d85..838e2d6 100644 --- a/frontend/src/page/HomePage.tsx +++ b/frontend/src/page/HomePage.tsx @@ -6,6 +6,7 @@ import {Reminder} from "../types/Reminder.ts"; import {ReminderDTO} from "../types/ReminderDTO.ts"; import {ChangeEvent, useState} from "react"; import AddAReminder from "../components/AddAReminder.tsx"; +import UpcomingReminderGallery from "../components/UpcomingReminderGallery.tsx"; type HomePageProps = { user: string | null | undefined, @@ -34,6 +35,7 @@ export default function HomePage(props: Readonly){ return(
+
{ From e94d8b4c1805d09b62d590aef55acab939177d77 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Thu, 4 Jul 2024 10:11:04 +0200 Subject: [PATCH 07/15] Frontend (with bug version): - add "showUpcomingReminder" State in UpcomingReminderGallery.tsx --- .../components/UpcomingReminderGallery.tsx | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/frontend/src/components/UpcomingReminderGallery.tsx b/frontend/src/components/UpcomingReminderGallery.tsx index f1ed565..c7b33b3 100644 --- a/frontend/src/components/UpcomingReminderGallery.tsx +++ b/frontend/src/components/UpcomingReminderGallery.tsx @@ -3,39 +3,57 @@ import {Reminder} from "../types/Reminder.ts"; import axios from "axios"; export default function UpcomingReminderGallery() { - const [upcomingReminders, setUpcomingReminders] = useState([]) + const [upcomingReminders, setUpcomingReminders] = useState([]); + const [showUpcomingReminder, setShowUpcomingReminder] = useState(false); useEffect(() => { - getUpcomingReminders() - const interval = setInterval(() => {getUpcomingReminders(); + getUpcomingReminders(); + + const interval = setInterval(() => { + getUpcomingReminders(); }, 60000); - return () => clearInterval(interval); + return () => clearInterval(interval); //Cleanup the interval on unmount }, []); const getUpcomingReminders = () => { - axios.get("api/reminders/upcoming") - .then(response => setUpcomingReminders(response.data)) - .catch(error => console.error("Error getting upcoming reminders", error)) - .finally(() => { - console.log("getUpcomingReminder_successful") + axios.get("/api/reminders/upcoming") + .then(response => { + if(response.data.length > 0) { + setUpcomingReminders(response.data); + setShowUpcomingReminder(true); + } }) + .catch(error => console.error("Error getting upcoming reminders", error)) + .finally(() => {console.log("getUpcomingReminder_successful")}) + } + + const handleClose = () => { + setShowUpcomingReminder(false); + setUpcomingReminders([]); } return(
-

Upcoming Reminders

-
    - {upcomingReminders.map(reminder => ( -
  • - {reminder.name} at {reminder.date} {reminder.time} -
  • - ))} -
+ {showUpcomingReminder && ( +
+

Upcoming Reminders

+
    + {upcomingReminders.map(reminder => ( +
  • + {reminder.name} at {reminder.date} {reminder.time} +
  • + ))} +
+ +
+ ) + }
+ ) } From 6b5594234fb2a781425c67844e8742d6b3270332 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Thu, 4 Jul 2024 11:50:53 +0200 Subject: [PATCH 08/15] Frontend: revise the bug(alarm doesn't work for more upcoming reminders) - change setUpcomingReminders(response.data) to setUpcomingReminders(preReminders => [...preReminders, ...response.data]); --- frontend/src/components/UpcomingReminderGallery.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/UpcomingReminderGallery.tsx b/frontend/src/components/UpcomingReminderGallery.tsx index c7b33b3..18cd5ba 100644 --- a/frontend/src/components/UpcomingReminderGallery.tsx +++ b/frontend/src/components/UpcomingReminderGallery.tsx @@ -23,7 +23,8 @@ export default function UpcomingReminderGallery() { axios.get("/api/reminders/upcoming") .then(response => { if(response.data.length > 0) { - setUpcomingReminders(response.data); + //setUpcomingReminders(response.data); + setUpcomingReminders(preReminders => [...preReminders, ...response.data]); setShowUpcomingReminder(true); } }) From 7d7f1b10fc918073c3622ba5de59f1a6275762ec Mon Sep 17 00:00:00 2001 From: tingSHI Date: Thu, 4 Jul 2024 14:45:49 +0200 Subject: [PATCH 09/15] Backend: - Add Unit test for "CheckReminders" in ReminderScheduler - Add Unit test for "getUpcomingReminders" in ReminderService --- .../reminder/ReminderSchedulerUnitTest.java | 47 +++++++++++++++++++ .../backend/reminder/ReminderServiceTest.java | 19 ++++++++ 2 files changed, 66 insertions(+) create mode 100644 backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderSchedulerUnitTest.java diff --git a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderSchedulerUnitTest.java b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderSchedulerUnitTest.java new file mode 100644 index 0000000..a4b71fd --- /dev/null +++ b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderSchedulerUnitTest.java @@ -0,0 +1,47 @@ +package com.github.tingshi2015.backend.reminder; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +import static org.mockito.Mockito.*; + +class ReminderSchedulerUnitTest { + ReminderService reminderService = mock(ReminderService.class); + NotificationService notificationService = mock(NotificationService.class); + ReminderScheduler reminderScheduler = new ReminderScheduler(reminderService, notificationService); + + + @Test + void checkReminders() { + //GIVEN + Reminder reminder1 = new Reminder("id1", "Drink Water!", LocalTime.now().withSecond(0).withNano(0), LocalDate.now()); + Reminder reminder2 = new Reminder("id2", "Call Mama & Papa!",LocalTime.now().withSecond(0).withNano(0), LocalDate.now()); + + List reminders = List.of(reminder1, reminder2); + + when(reminderService.getUpcomingReminders()).thenReturn(reminders); + //doNothing().when(notificationService).sendNotification(reminder1); //---can be omitted! + //doNothing().when(notificationService).sendNotification(reminder2); //---can be omitted! + + //WHEN + reminderScheduler.checkReminders(); + + //THEN + verify(notificationService, times(1)).sendNotification(reminder1); + verify(notificationService, times(1)).sendNotification(reminder2); + + + } + +} + + + + diff --git a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java index b9ff7cc..7ea5a60 100644 --- a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java +++ b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java @@ -6,6 +6,7 @@ import java.time.LocalTime; import java.util.List; import java.util.NoSuchElementException; +import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -117,4 +118,22 @@ void updateAReminder_withInvalidId_shouldThrowException(){ assertEquals("Reminder with id: " + id + " not found. Can't update!", exception.getMessage()); } + + @Test + void getUpcomingReminders(){ + //GIVEN + Reminder upcomingReminder1 = new Reminder("id1", "Drink Water!", LocalTime.now().withSecond(0).withNano(0), LocalDate.now()); + Reminder upcomingReminder2 = new Reminder("id2", "Call Mama & Papa!",LocalTime.now().withSecond(0).withNano(0), LocalDate.now()); + List upcomingReminders = List.of(upcomingReminder1, upcomingReminder2); + + when(reminderRepository.findAll()).thenReturn(upcomingReminders); + + //WHEN + List actual = reminderService.getUpcomingReminders(); + + //THEN + verify(reminderRepository).findAll(); + assertEquals(upcomingReminders, actual); + } + } \ No newline at end of file From a5b151f2cfd4d728fc221e05741f3b9f1ddf1f2b Mon Sep 17 00:00:00 2001 From: tingSHI Date: Thu, 4 Jul 2024 17:38:15 +0200 Subject: [PATCH 10/15] Backend: - Add Integration tests - revise the bug for logout(change logoutUrl from ("/logout") to ("/api/logout") in SecurityConfig.java Frontend: - revise the bug for logout(change logoutUrl from ("/logout") to ("/api/logout") in Header.tsx --- .../backend/security/SecurityConfig.java | 2 +- .../ReminderControllerIntegrationTest.java | 39 ++++++++++++++++++- .../reminder/ReminderSchedulerUnitTest.java | 4 -- .../backend/reminder/ReminderServiceTest.java | 2 +- frontend/src/components/Header.tsx | 2 +- frontend/src/page/HomePage.tsx | 2 + 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/backend/src/main/java/com/github/tingshi2015/backend/security/SecurityConfig.java b/backend/src/main/java/com/github/tingshi2015/backend/security/SecurityConfig.java index 1d2892a..ecdd074 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/security/SecurityConfig.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/security/SecurityConfig.java @@ -32,7 +32,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) .oauth2Login(o -> o.defaultSuccessUrl(appUrl)) .logout(l -> l - .logoutUrl("/logout") + .logoutUrl("/api/logout") .logoutSuccessUrl("/login") .invalidateHttpSession(true) .clearAuthentication(true) diff --git a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderControllerIntegrationTest.java b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderControllerIntegrationTest.java index 60058e8..04612a5 100644 --- a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderControllerIntegrationTest.java +++ b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderControllerIntegrationTest.java @@ -9,10 +9,12 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.web.bind.annotation.GetMapping; import java.time.LocalDate; import java.time.LocalTime; +import java.util.List; @SpringBootTest @AutoConfigureMockMvc @@ -134,4 +136,39 @@ void putAReminder() throws Exception { } -} \ No newline at end of file + @Test + @DirtiesContext + void getUpcomingReminders() throws Exception { + //GIVEN + LocalTime upcomingReminder1LocalTime = LocalTime.now().withSecond(0).withNano(0); + LocalDate upcomingReminder1LocalDate = LocalDate.now(); + LocalDate upcomingReminder2LocalDate = LocalDate.now(); + LocalTime upcomingReminder2LocalTime = LocalTime.now().withSecond(0).withNano(0); + Reminder upcomingReminder1 = new Reminder("id1", "Drink Water!", upcomingReminder1LocalTime, upcomingReminder1LocalDate); + Reminder upcomingReminder2 = new Reminder("id2", "Call Mama & Papa!",upcomingReminder2LocalTime, upcomingReminder2LocalDate); + reminderRepository.save(upcomingReminder1); + reminderRepository.save(upcomingReminder2); + + //WHEN + mockMvc.perform(MockMvcRequestBuilders.get("/api/reminders/upcoming")) + //THEN + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().json(""" + [ + { + "id": "id1", + "name": "Drink Water!" + }, + { + "id": "id2", + "name": "Call Mama & Papa!" + } + ] + """)) + .andExpect(MockMvcResultMatchers.jsonPath("*.time").isNotEmpty()) + .andExpect(MockMvcResultMatchers.jsonPath("*.date").isNotEmpty()); + } + } + + + diff --git a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderSchedulerUnitTest.java b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderSchedulerUnitTest.java index a4b71fd..fb40a3e 100644 --- a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderSchedulerUnitTest.java +++ b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderSchedulerUnitTest.java @@ -1,10 +1,6 @@ package com.github.tingshi2015.backend.reminder; -import lombok.RequiredArgsConstructor; import org.junit.jupiter.api.Test; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; import java.time.LocalDate; import java.time.LocalTime; diff --git a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java index 7ea5a60..7337798 100644 --- a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java +++ b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java @@ -6,7 +6,7 @@ import java.time.LocalTime; import java.util.List; import java.util.NoSuchElementException; -import java.util.stream.Collectors; + import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index 50090ef..25d5925 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -12,7 +12,7 @@ export default function Header(props: Readonly){ const navigate = useNavigate(); const logout = () => { - axios.get("/logout") + axios.get("/api/logout") .then(()=>{navigate("/login")}) .catch(error => console.error("Logout failed",error)) } diff --git a/frontend/src/page/HomePage.tsx b/frontend/src/page/HomePage.tsx index 838e2d6..a0cc548 100644 --- a/frontend/src/page/HomePage.tsx +++ b/frontend/src/page/HomePage.tsx @@ -24,6 +24,8 @@ export default function HomePage(props: Readonly){ setQuery(event.target.value) } + console.log(props) + const filteredReminders = props.reminders.filter( reminder => reminder.name.toLowerCase().includes(query.toLowerCase()) || From 6b226a3b3677bdf4cc0e045147d4eb62615b78d7 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Thu, 4 Jul 2024 17:43:18 +0200 Subject: [PATCH 11/15] Backend: - delete unused import --- .../backend/reminder/ReminderControllerIntegrationTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderControllerIntegrationTest.java b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderControllerIntegrationTest.java index 04612a5..7c601f3 100644 --- a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderControllerIntegrationTest.java +++ b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderControllerIntegrationTest.java @@ -9,12 +9,11 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import org.springframework.web.bind.annotation.GetMapping; import java.time.LocalDate; import java.time.LocalTime; -import java.util.List; + @SpringBootTest @AutoConfigureMockMvc From 63c12c9587eb55bf142c66cd180d1978a693d442 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Thu, 4 Jul 2024 17:47:59 +0200 Subject: [PATCH 12/15] Backend: - delete unused method "convertToDTO" in ReminderService.java --- .../tingshi2015/backend/reminder/ReminderService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java index 6645ee6..22b7b60 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java @@ -16,9 +16,9 @@ public class ReminderService { private final ReminderRepository reminderRepository; private final IdService idService; - private ReminderDTO convertToDTO(Reminder reminder){ - return new ReminderDTO(reminder.name(), reminder.time(),reminder.date()); - } +// private ReminderDTO convertToDTO(Reminder reminder){ +// return new ReminderDTO(reminder.name(), reminder.time(),reminder.date()); +// } private Reminder convertToEntity(ReminderDTO reminderDTO){ String id = idService.randomId(); From be53fc902d442dfe9a095c6bd583e38f4e9f6352 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Thu, 4 Jul 2024 18:53:28 +0200 Subject: [PATCH 13/15] Backend: - Add Unit Test for getUpcomingReminders_whenTimeOrDateAreNull --- .../reminder/NotificationServiceTest.java | 39 +++++++++++++++++++ .../backend/reminder/ReminderServiceTest.java | 22 ++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 backend/src/test/java/com/github/tingshi2015/backend/reminder/NotificationServiceTest.java diff --git a/backend/src/test/java/com/github/tingshi2015/backend/reminder/NotificationServiceTest.java b/backend/src/test/java/com/github/tingshi2015/backend/reminder/NotificationServiceTest.java new file mode 100644 index 0000000..d7b49a8 --- /dev/null +++ b/backend/src/test/java/com/github/tingshi2015/backend/reminder/NotificationServiceTest.java @@ -0,0 +1,39 @@ +//package com.github.tingshi2015.backend.reminder; +// +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +// +//import java.io.ByteArrayInputStream; +//import java.io.PrintStream; +//import java.time.LocalDate; +//import java.time.LocalTime; +// +//import static org.junit.jupiter.api.Assertions.*; +// +//class NotificationServiceTest { +// private final ByteArrayInputStream outContent = new ByteArrayInputStream(); +// private final PrintStream originalOut = System.out; +// private NotificationService notificationService; +// +// @BeforeEach +// void setUp(){ +// notificationService = new NotificationService(); +// System.setOut(new PrintStream(outContent)); +// } +// +// @Test +// void sendNotification() { +// +// //GIVEN +// Reminder reminder = new Reminder("id1", "Buy ice cream!", LocalTime.of(14, 30), LocalDate.of(2024, 7, 4)); +// +// //WHEN +// notificationService.sendNotification(reminder); +// +// //THEN +// String expectedOutput = "Reminder Alert: Buy ice cream! at 14:30, 2024-07-04"; +// assertEquals(expectedOutput, notificationService.sendNotification(reminder)); +// } +//} + + diff --git a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java index 7337798..7b51221 100644 --- a/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java +++ b/backend/src/test/java/com/github/tingshi2015/backend/reminder/ReminderServiceTest.java @@ -120,7 +120,7 @@ void updateAReminder_withInvalidId_shouldThrowException(){ @Test - void getUpcomingReminders(){ + void getUpcomingReminders_whenTimeAndDateAreNotNull(){ //GIVEN Reminder upcomingReminder1 = new Reminder("id1", "Drink Water!", LocalTime.now().withSecond(0).withNano(0), LocalDate.now()); Reminder upcomingReminder2 = new Reminder("id2", "Call Mama & Papa!",LocalTime.now().withSecond(0).withNano(0), LocalDate.now()); @@ -136,4 +136,24 @@ void getUpcomingReminders(){ assertEquals(upcomingReminders, actual); } + @Test + void getUpcomingReminders_whenTimeOrDateAreNull(){ + //GIVEN + Reminder reminderWithoutNull = new Reminder("id1", "Buy milk!", LocalTime.now().withSecond(0).withNano(0), LocalDate.now()); + Reminder reminderWithNullDate = new Reminder("id2", "Drink Water!", LocalTime.now().withSecond(0).withNano(0), null); + Reminder reminderWithNullTime = new Reminder("id3", "Call Mama & Papa!",null, LocalDate.now()); + Reminder reminderWithNullDateAndTime = new Reminder("id4", "Call Mama & Papa!",null, null); + List reminders = List.of(reminderWithoutNull, reminderWithNullDate, reminderWithNullTime, reminderWithNullDateAndTime); + + when(reminderRepository.findAll()).thenReturn(reminders); + + //WHEN + List actual = reminderService.getUpcomingReminders(); + + //THEN + verify(reminderRepository).findAll(); + List expected = List.of(reminderWithoutNull); + assertEquals(expected, actual); + } + } \ No newline at end of file From a2a0c582a4e2c3d82556dde819d862fdddab3e63 Mon Sep 17 00:00:00 2001 From: tingSHI Date: Thu, 4 Jul 2024 19:07:26 +0200 Subject: [PATCH 14/15] Backend: - Delete insignificant unfinished Unit Test for NotificationService --- .../reminder/NotificationServiceTest.java | 39 ------------------- 1 file changed, 39 deletions(-) delete mode 100644 backend/src/test/java/com/github/tingshi2015/backend/reminder/NotificationServiceTest.java diff --git a/backend/src/test/java/com/github/tingshi2015/backend/reminder/NotificationServiceTest.java b/backend/src/test/java/com/github/tingshi2015/backend/reminder/NotificationServiceTest.java deleted file mode 100644 index d7b49a8..0000000 --- a/backend/src/test/java/com/github/tingshi2015/backend/reminder/NotificationServiceTest.java +++ /dev/null @@ -1,39 +0,0 @@ -//package com.github.tingshi2015.backend.reminder; -// -//import org.junit.jupiter.api.BeforeEach; -//import org.junit.jupiter.api.Test; -// -//import java.io.ByteArrayInputStream; -//import java.io.PrintStream; -//import java.time.LocalDate; -//import java.time.LocalTime; -// -//import static org.junit.jupiter.api.Assertions.*; -// -//class NotificationServiceTest { -// private final ByteArrayInputStream outContent = new ByteArrayInputStream(); -// private final PrintStream originalOut = System.out; -// private NotificationService notificationService; -// -// @BeforeEach -// void setUp(){ -// notificationService = new NotificationService(); -// System.setOut(new PrintStream(outContent)); -// } -// -// @Test -// void sendNotification() { -// -// //GIVEN -// Reminder reminder = new Reminder("id1", "Buy ice cream!", LocalTime.of(14, 30), LocalDate.of(2024, 7, 4)); -// -// //WHEN -// notificationService.sendNotification(reminder); -// -// //THEN -// String expectedOutput = "Reminder Alert: Buy ice cream! at 14:30, 2024-07-04"; -// assertEquals(expectedOutput, notificationService.sendNotification(reminder)); -// } -//} - - From 25c66ca36afe410886b260f46fac3e1154398e7c Mon Sep 17 00:00:00 2001 From: tingSHI Date: Fri, 5 Jul 2024 12:24:50 +0200 Subject: [PATCH 15/15] Backend: - Add the idea with @Query for Alarm --- .../backend/reminder/ReminderRepository.java | 9 ++++++++ .../backend/reminder/ReminderService.java | 21 +++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderRepository.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderRepository.java index 8be0d09..a5969ce 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderRepository.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderRepository.java @@ -1,9 +1,18 @@ package com.github.tingshi2015.backend.reminder; import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; import org.springframework.stereotype.Repository; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + @Repository public interface ReminderRepository extends MongoRepository { +// @Query("{'date': ?0, 'time': {$gte: ?1, $lt: ?2}}") +// List findRemindersByDateAndTime(LocalDate date, LocalTime startTime, LocalTime endTime); + + } diff --git a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java index 22b7b60..2508cbc 100644 --- a/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java +++ b/backend/src/main/java/com/github/tingshi2015/backend/reminder/ReminderService.java @@ -20,9 +20,9 @@ public class ReminderService { // return new ReminderDTO(reminder.name(), reminder.time(),reminder.date()); // } - private Reminder convertToEntity(ReminderDTO reminderDTO){ + private Reminder convertToEntity(ReminderDTO reminderDTO) { String id = idService.randomId(); - return new Reminder(id, reminderDTO.name(),reminderDTO.time(),reminderDTO.date()); + return new Reminder(id, reminderDTO.name(), reminderDTO.time(), reminderDTO.date()); } public List getAllReminders() { @@ -35,14 +35,14 @@ public Reminder createAReminder(ReminderDTO reminderDTO) { } public void deleteAReminder(String id) { - if (!reminderRepository.existsById(id)){ + if (!reminderRepository.existsById(id)) { throw new NoSuchElementException("Reminder with id: " + id + " not found. Can't delete!"); } reminderRepository.deleteById(id); } public Reminder updateAReminder(ReminderDTO updateReminder, String id) { - if(!reminderRepository.existsById(id)){ + if (!reminderRepository.existsById(id)) { throw new NoSuchElementException("Reminder with id: " + id + " not found. Can't update!"); } Reminder reminderToUpdate = new Reminder(id, updateReminder.name(), updateReminder.time(), updateReminder.date()); @@ -55,6 +55,7 @@ public Reminder updateAReminder(ReminderDTO updateReminder, String id) { // .orElseThrow(()-> new NoSuchElementException("Reminder with id: " + id + " not found. Can't getReminderById")); // } +//----------inefficient method with "filter"!--------------- public List getUpcomingReminders() { LocalDate today = LocalDate.now(); LocalTime now = LocalTime.now().withSecond(0).withNano(0); //ignore second & Nano-second @@ -64,4 +65,16 @@ public List getUpcomingReminders() { .filter(reminder -> reminder.date().equals(today) && reminder.time().withSecond(0).withNano(0).equals(now)) .collect(Collectors.toList()); } + +//---------efficient method with "@Query"------------------ +/* + public List getUpcomingReminders() { + LocalDate today = LocalDate.now(); + LocalTime now = LocalTime.now().withSecond(0).withNano(0); //ignore second & Nano-second + LocalTime nextMinute = now.plusMinutes(1); + + return reminderRepository.findRemindersByDateAndTime(today, now, nextMinute); + } +*/ + }