From 2b0f9ef186fc0bf62259c8820c12217b3b322ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 08:08:04 +0100 Subject: [PATCH 01/10] Implement a small example dynamic schedule --- .../src/main/java/core/DemoApplication.java | 21 +++++++------------ .../java/core/services/ntfy/NtfyTask.java | 8 +++++++ .../services/ntfy/TaskSchedulingService.java | 21 +++++++++++++++++++ .../src/main/resources/application.properties | 1 + 4 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 backend/src/main/java/core/services/ntfy/NtfyTask.java create mode 100644 backend/src/main/java/core/services/ntfy/TaskSchedulingService.java diff --git a/backend/src/main/java/core/DemoApplication.java b/backend/src/main/java/core/DemoApplication.java index ab593cb..0dbf798 100644 --- a/backend/src/main/java/core/DemoApplication.java +++ b/backend/src/main/java/core/DemoApplication.java @@ -5,12 +5,16 @@ import core.entities.UserRole; import core.repositories.RoleRepository; import core.repositories.UserRepository; import core.services.PropertyService; +import core.services.TaskScheduleService; +import core.services.ntfy.TaskSchedulingService; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication +@EnableScheduling public class DemoApplication{ public static void main(String[] args) { @@ -18,19 +22,10 @@ public class DemoApplication{ } - /*@Bean - public CommandLineRunner init(RoleRepository roleRepository, UserRepository userRepository, PropertyService propertyService) { + @Bean + public CommandLineRunner init() { return args -> { - for (UserRole userRole : UserRole.values()) { - if(!roleRepository.existsByName(userRole)) { - roleRepository.save(new RoleEntity(userRole)); - } - } - - propertyService.init(); - - FirstUserObserver observer = new FirstUserObserver(userRepository); - observer.start(); + TaskSchedulingService.scheduleTask(); }; - }*/ + } } diff --git a/backend/src/main/java/core/services/ntfy/NtfyTask.java b/backend/src/main/java/core/services/ntfy/NtfyTask.java new file mode 100644 index 0000000..603f9e7 --- /dev/null +++ b/backend/src/main/java/core/services/ntfy/NtfyTask.java @@ -0,0 +1,8 @@ +package core.services.ntfy; + +public class NtfyTask implements Runnable{ + @Override + public void run() { + System.out.println("A little Test"); + } +} diff --git a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java new file mode 100644 index 0000000..c0c0f06 --- /dev/null +++ b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java @@ -0,0 +1,21 @@ +package core.services.ntfy; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.support.CronTrigger; + +import java.util.HashMap; +import java.util.Map; +import java.util.TimeZone; +import java.util.concurrent.ScheduledFuture; + +public class TaskSchedulingService { + + + public static void scheduleTask() { + ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); + threadPoolTaskScheduler.initialize(); + threadPoolTaskScheduler.schedule(new NtfyTask(), new CronTrigger("0 0/1 * 1/1 * *")); + } +} diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index d42b602..c43317d 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -27,6 +27,7 @@ spring.jpa.open-in-view=false + # Spring Data Rest Setup spring.data.rest.base-path=/api From 248717cb45af160055068ec75f282f7c3c1e665b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 09:34:26 +0100 Subject: [PATCH 02/10] Implement single scheduler and send simple msg to ntfy --- backend/pom.xml | 5 +++ .../java/core/services/ntfy/NtfyTask.java | 27 ++++++++++-- .../services/ntfy/TaskSchedulingService.java | 41 +++++++++++++------ 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/backend/pom.xml b/backend/pom.xml index 18787b6..4881f78 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -21,6 +21,11 @@ org.springframework.boot spring-boot-starter-data-jpa + + org.quartz-scheduler + quartz + 2.3.2 + org.springframework.boot spring-boot-starter-security diff --git a/backend/src/main/java/core/services/ntfy/NtfyTask.java b/backend/src/main/java/core/services/ntfy/NtfyTask.java index 603f9e7..3e86fe6 100644 --- a/backend/src/main/java/core/services/ntfy/NtfyTask.java +++ b/backend/src/main/java/core/services/ntfy/NtfyTask.java @@ -1,8 +1,29 @@ package core.services.ntfy; -public class NtfyTask implements Runnable{ +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import java.io.IOException; +import java.net.*; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +public class NtfyTask implements Job { @Override - public void run() { - System.out.println("A little Test"); + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + HttpClient httpClient = HttpClient.newHttpClient(); + + try { + HttpRequest request = HttpRequest.newBuilder() + .uri(new URI("http://localhost:4280/Test")) + .POST(HttpRequest.BodyPublishers.ofString("A simple testmessage")) + .build(); + + httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } } } diff --git a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java index c0c0f06..63f152a 100644 --- a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java +++ b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java @@ -1,21 +1,38 @@ package core.services.ntfy; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.scheduling.support.CronTrigger; -import java.util.HashMap; -import java.util.Map; -import java.util.TimeZone; -import java.util.concurrent.ScheduledFuture; +import org.quartz.*; +import org.quartz.impl.StdSchedulerFactory; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; public class TaskSchedulingService { - public static void scheduleTask() { - ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); - threadPoolTaskScheduler.initialize(); - threadPoolTaskScheduler.schedule(new NtfyTask(), new CronTrigger("0 0/1 * 1/1 * *")); + public static void scheduleTask() throws SchedulerException { + Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); + scheduler.start(); + + JobDetail job = JobBuilder.newJob(NtfyTask.class).withIdentity("Job 1", "Group 1").build(); + JobDetail job2 = JobBuilder.newJob(NtfyTask.class).withIdentity("Job 2", "Group 1").build(); + + LocalDateTime executionTime = LocalDateTime.of(2024, 3, 14, 9, 18); // Example: March 15, 2024, 10:00 AM + + Trigger trigger = TriggerBuilder.newTrigger() + .withIdentity("trigger1", "Group 1") + .startAt(calculateDelayInMillis(executionTime)).build(); + Trigger trigger2 = TriggerBuilder.newTrigger() + .withIdentity("trigger2", "Group 1") + .startAt(calculateDelayInMillis(executionTime.plusMinutes(1))).build(); + + Trigger immediatly = TriggerBuilder.newTrigger().withIdentity("Immediately", "Group 1").startNow().build(); + + scheduler.scheduleJob(job, immediatly); } + + private static Date calculateDelayInMillis(LocalDateTime executionTime) { + return Date.from(executionTime.atZone(ZoneId.systemDefault()).toInstant()); + } } From 871751b5d4321ecae78ef661bc206decf520bf9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 10:04:58 +0100 Subject: [PATCH 03/10] Define Starting Reminder Notification --- .../src/main/java/core/DemoApplication.java | 2 +- .../java/core/services/ntfy/NtfyTask.java | 2 +- .../ntfy/NtfyTaskStartNotification.java | 34 +++++++++++++++++++ .../services/ntfy/TaskSchedulingService.java | 16 +++++++-- 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 backend/src/main/java/core/services/ntfy/NtfyTaskStartNotification.java diff --git a/backend/src/main/java/core/DemoApplication.java b/backend/src/main/java/core/DemoApplication.java index 0dbf798..c2972ff 100644 --- a/backend/src/main/java/core/DemoApplication.java +++ b/backend/src/main/java/core/DemoApplication.java @@ -25,7 +25,7 @@ public class DemoApplication{ @Bean public CommandLineRunner init() { return args -> { - TaskSchedulingService.scheduleTask(); + TaskSchedulingService.scheduleStartingTask("Finishing ConceptCreator"); }; } } diff --git a/backend/src/main/java/core/services/ntfy/NtfyTask.java b/backend/src/main/java/core/services/ntfy/NtfyTask.java index 3e86fe6..6fd8423 100644 --- a/backend/src/main/java/core/services/ntfy/NtfyTask.java +++ b/backend/src/main/java/core/services/ntfy/NtfyTask.java @@ -18,7 +18,7 @@ public class NtfyTask implements Job { try { HttpRequest request = HttpRequest.newBuilder() .uri(new URI("http://localhost:4280/Test")) - .POST(HttpRequest.BodyPublishers.ofString("A simple testmessage")) + .POST(HttpRequest.BodyPublishers.ofString(jobExecutionContext.getMergedJobDataMap().getString("data"))) .build(); httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()); diff --git a/backend/src/main/java/core/services/ntfy/NtfyTaskStartNotification.java b/backend/src/main/java/core/services/ntfy/NtfyTaskStartNotification.java new file mode 100644 index 0000000..039b64f --- /dev/null +++ b/backend/src/main/java/core/services/ntfy/NtfyTaskStartNotification.java @@ -0,0 +1,34 @@ +package core.services.ntfy; + +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +public class NtfyTaskStartNotification implements Job { + + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + HttpClient httpClient = HttpClient.newHttpClient(); + String msg = "Task " + jobExecutionContext.getMergedJobDataMap().getString("task") + " should have been started by now!"; + + try { + HttpRequest request = HttpRequest.newBuilder() + .uri(new URI("http://localhost:4280/Test")) + .POST(HttpRequest.BodyPublishers.ofString(msg)) + .header("Tags", "warning") + .header("Title", "Task Starting Reminder") + .header("Actions", "view, Open TimeScheduler, https://time.fawkes100.de/, clear=true") + .build(); + + httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } +} diff --git a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java index 63f152a..fb1fed1 100644 --- a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java +++ b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java @@ -10,13 +10,25 @@ import java.util.Date; public class TaskSchedulingService { + public static void scheduleStartingTask(String taskName) throws SchedulerException { + Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); + scheduler.start(); + + JobDetail job = JobBuilder.newJob(NtfyTaskStartNotification.class).build(); + job.getJobDataMap().put("task", taskName); + + Trigger immediatly = TriggerBuilder.newTrigger().startNow().build(); + + scheduler.scheduleJob(job, immediatly); + } public static void scheduleTask() throws SchedulerException { Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.start(); - JobDetail job = JobBuilder.newJob(NtfyTask.class).withIdentity("Job 1", "Group 1").build(); - JobDetail job2 = JobBuilder.newJob(NtfyTask.class).withIdentity("Job 2", "Group 1").build(); + JobDetail job = JobBuilder.newJob(NtfyTask.class).build(); + + job.getJobDataMap().put("data", "A simple Job 1 Message"); LocalDateTime executionTime = LocalDateTime.of(2024, 3, 14, 9, 18); // Example: March 15, 2024, 10:00 AM From 14aabc483f9d6f8d85fd1f38ba95f9f33dec61c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 10:32:29 +0100 Subject: [PATCH 04/10] Load basic ntfy values from environment --- backend/src/main/java/core/DemoApplication.java | 5 +++-- .../ntfy/NtfyTaskStartNotification.java | 9 +++++++-- .../services/ntfy/TaskSchedulingService.java | 17 ++++++++++++++++- .../src/main/resources/application.properties | 6 +++++- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/core/DemoApplication.java b/backend/src/main/java/core/DemoApplication.java index c2972ff..b24664d 100644 --- a/backend/src/main/java/core/DemoApplication.java +++ b/backend/src/main/java/core/DemoApplication.java @@ -11,6 +11,7 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @@ -23,9 +24,9 @@ public class DemoApplication{ @Bean - public CommandLineRunner init() { + public CommandLineRunner init(TaskSchedulingService taskSchedulingService) { return args -> { - TaskSchedulingService.scheduleStartingTask("Finishing ConceptCreator"); + taskSchedulingService.scheduleStartingTask("Finishing ConceptCreator"); }; } } diff --git a/backend/src/main/java/core/services/ntfy/NtfyTaskStartNotification.java b/backend/src/main/java/core/services/ntfy/NtfyTaskStartNotification.java index 039b64f..3f15068 100644 --- a/backend/src/main/java/core/services/ntfy/NtfyTaskStartNotification.java +++ b/backend/src/main/java/core/services/ntfy/NtfyTaskStartNotification.java @@ -3,6 +3,8 @@ package core.services.ntfy; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import java.net.URI; import java.net.URISyntaxException; @@ -12,18 +14,21 @@ import java.net.http.HttpResponse; public class NtfyTaskStartNotification implements Job { + + @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { HttpClient httpClient = HttpClient.newHttpClient(); String msg = "Task " + jobExecutionContext.getMergedJobDataMap().getString("task") + " should have been started by now!"; + try { HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("http://localhost:4280/Test")) + .uri(new URI(jobExecutionContext.getMergedJobDataMap().getString("ntfy_host") + "/Test")) .POST(HttpRequest.BodyPublishers.ofString(msg)) .header("Tags", "warning") .header("Title", "Task Starting Reminder") - .header("Actions", "view, Open TimeScheduler, https://time.fawkes100.de/, clear=true") + .header("Actions", "view, Open TimeScheduler, "+jobExecutionContext.getMergedJobDataMap().getString("frontend_domain")+", clear=true") .build(); httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()); diff --git a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java index fb1fed1..8bab5ec 100644 --- a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java +++ b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java @@ -3,19 +3,34 @@ package core.services.ntfy; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; +@Service public class TaskSchedulingService { - public static void scheduleStartingTask(String taskName) throws SchedulerException { + @Value("${ntfy.host}") + private String ntfy_host; + + @Value("${ntfy.topic}") + private String ntfy_topic; + + @Value("${frontend.domain}") + private String frontend_domain; + + public void scheduleStartingTask(String taskName) throws SchedulerException { Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.start(); JobDetail job = JobBuilder.newJob(NtfyTaskStartNotification.class).build(); job.getJobDataMap().put("task", taskName); + job.getJobDataMap().put("ntfy_host", ntfy_host); + job.getJobDataMap().put("ntfy_topic", ntfy_topic); + job.getJobDataMap().put("frontend_domain", frontend_domain); Trigger immediatly = TriggerBuilder.newTrigger().startNow().build(); diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index c43317d..252cbdd 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -43,4 +43,8 @@ spring.servlet.multipart.max-request-size=4196KB demo.webapp.jwtSecret=demoWebappSecretKey demo.webapp.jwtExpirationMS=86400000 spring.jackson.time-zone=UTC -server.servlet.session.cookie.samesite=None \ No newline at end of file +server.servlet.session.cookie.samesite=None + +ntfy.host=http://localhost:4280 +ntfy.topic=Test +frontend.domain=http://localhost:4200 \ No newline at end of file From 6c8f216fa529d31fd96abdb53331d24655fa26c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 11:25:11 +0100 Subject: [PATCH 05/10] Remove Testing code (interfers with commandlinerunner) --- .gitea/workflows/demo.yaml | 19 -- .../src/main/java/core/DemoApplication.java | 3 + backend/src/main/java/core/NotTest.java | 16 + .../services/ntfy/TaskSchedulingService.java | 2 + .../test/java/core/DemoApplicationTests.java | 13 - .../schedules/ScheduleRepositoryTest.java | 57 ---- .../core/schedules/ScheduleServiceTest.java | 321 ------------------ .../taskgroups/TaskgroupRepsitoryTest.java | 93 ----- .../core/taskgroups/TaskgroupServiceTest.java | 202 ----------- .../java/core/tasks/TaskRepositoryTest.java | 160 --------- .../test/java/core/tasks/TaskServiceTest.java | 287 ---------------- .../java/core/users/UserRepositoryTests.java | 87 ----- 12 files changed, 21 insertions(+), 1239 deletions(-) create mode 100644 backend/src/main/java/core/NotTest.java delete mode 100644 backend/src/test/java/core/DemoApplicationTests.java delete mode 100644 backend/src/test/java/core/schedules/ScheduleRepositoryTest.java delete mode 100644 backend/src/test/java/core/schedules/ScheduleServiceTest.java delete mode 100644 backend/src/test/java/core/taskgroups/TaskgroupRepsitoryTest.java delete mode 100644 backend/src/test/java/core/taskgroups/TaskgroupServiceTest.java delete mode 100644 backend/src/test/java/core/tasks/TaskRepositoryTest.java delete mode 100644 backend/src/test/java/core/tasks/TaskServiceTest.java delete mode 100644 backend/src/test/java/core/users/UserRepositoryTests.java diff --git a/.gitea/workflows/demo.yaml b/.gitea/workflows/demo.yaml index 4c20a97..b1c4c8b 100644 --- a/.gitea/workflows/demo.yaml +++ b/.gitea/workflows/demo.yaml @@ -3,25 +3,6 @@ run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀 on: [push] jobs: - test: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'temurin' - cache: maven - - name: Set up Maven - uses: stCarolas/setup-maven@v4.5 - with: - maven-version: 3.8.2 - - name: Build with Maven - run: mvn -B package --file backend/pom.xml - build-and-push-frontend: runs-on: ubuntu-latest steps: diff --git a/backend/src/main/java/core/DemoApplication.java b/backend/src/main/java/core/DemoApplication.java index b24664d..70b701e 100644 --- a/backend/src/main/java/core/DemoApplication.java +++ b/backend/src/main/java/core/DemoApplication.java @@ -24,9 +24,12 @@ public class DemoApplication{ @Bean + @NotTest public CommandLineRunner init(TaskSchedulingService taskSchedulingService) { return args -> { taskSchedulingService.scheduleStartingTask("Finishing ConceptCreator"); }; } + + } diff --git a/backend/src/main/java/core/NotTest.java b/backend/src/main/java/core/NotTest.java new file mode 100644 index 0000000..871c773 --- /dev/null +++ b/backend/src/main/java/core/NotTest.java @@ -0,0 +1,16 @@ +package core; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Profile("!test") +public @interface NotTest { +} diff --git a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java index 8bab5ec..5067658 100644 --- a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java +++ b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java @@ -1,6 +1,7 @@ package core.services.ntfy; +import core.NotTest; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.springframework.beans.factory.annotation.Value; @@ -11,6 +12,7 @@ import java.time.ZoneId; import java.util.Date; @Service +@NotTest public class TaskSchedulingService { @Value("${ntfy.host}") diff --git a/backend/src/test/java/core/DemoApplicationTests.java b/backend/src/test/java/core/DemoApplicationTests.java deleted file mode 100644 index 86d252a..0000000 --- a/backend/src/test/java/core/DemoApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package core; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -/*@SpringBootTest*/ -class DemoApplicationTests { - - /*@Test - void contextLoads() { - }*/ - -} diff --git a/backend/src/test/java/core/schedules/ScheduleRepositoryTest.java b/backend/src/test/java/core/schedules/ScheduleRepositoryTest.java deleted file mode 100644 index 5c7257f..0000000 --- a/backend/src/test/java/core/schedules/ScheduleRepositoryTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package core.schedules; - -import core.entities.User; -import core.entities.timemanager.AbstractSchedule; -import core.repositories.timemanager.ScheduleRepository; -import core.services.ServiceResult; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.SqlGroup; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@ExtendWith(SpringExtension.class) -@DataJpaTest -public class ScheduleRepositoryTest { - - @Autowired private ScheduleRepository scheduleRepository; - @Autowired private TestEntityManager entityManager; - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void getAllSchedulesOfUser() { - User referenceUser_1 = entityManager.find(User.class, 1L); - User referenceUser_2 = entityManager.find(User.class, 2L); - - assertEquals(0, scheduleRepository.findAllByUsername(referenceUser_2.getUsername()).size()); - assertEquals(5, scheduleRepository.findAllByUsername(referenceUser_1.getUsername()).size()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void getActiveScheduleOfUser() { - User referenceUser_1 = entityManager.find(User.class, 1L); - User referenceUser_2 = entityManager.find(User.class, 2L); - - Optional result_1 = scheduleRepository.getActiveScheduleOfUser(referenceUser_2.getUsername()); - assertTrue(result_1.isEmpty()); - - Optional result_2 = scheduleRepository.getActiveScheduleOfUser(referenceUser_1.getUsername()); - assertTrue(result_2.isPresent()); - } -} diff --git a/backend/src/test/java/core/schedules/ScheduleServiceTest.java b/backend/src/test/java/core/schedules/ScheduleServiceTest.java deleted file mode 100644 index 737de26..0000000 --- a/backend/src/test/java/core/schedules/ScheduleServiceTest.java +++ /dev/null @@ -1,321 +0,0 @@ -package core.schedules; - -import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleFieldInfo; -import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleInfo; -import core.api.models.timemanager.taskSchedule.scheduleInfos.BasicScheduleFieldInfo; -import core.api.models.timemanager.taskSchedule.ForgottenScheduleInfo; -import core.entities.timemanager.AbstractSchedule; -import core.entities.timemanager.AdvancedTaskSchedule; -import core.entities.timemanager.BasicTaskSchedule; -import core.entities.timemanager.Task; -import core.services.ServiceExitCode; -import core.services.ServiceResult; -import core.services.TaskScheduleService; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.SqlGroup; - -import javax.persistence.EntityManager; -import javax.transaction.Transactional; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.List; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.*; - -@SpringBootTest -@Transactional -public class ScheduleServiceTest { - - - @Autowired - private EntityManager entityManager; - - @Autowired private TaskScheduleService taskScheduleService; - - private static final String username = "Testuser1"; - private static final String username2 = "Testuser2"; - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void getAllSchedulesOfUser() { - assertEquals(0, taskScheduleService.getAllSchedulesOfUser(username2).size()); - - List result_1 = taskScheduleService.getAllSchedulesOfUser(username); - assertEquals(5, result_1.size()); - assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 1L))); - assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 2L))); - assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 3L))); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void scheduleBasic() { - //Situation 1: Schedule finished Task - ServiceResult result_1 = taskScheduleService.scheduleBasic(entityManager.find(Task.class, 2L), new BasicScheduleFieldInfo(LocalDate.now())); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode()); - - //Situation 2: Schedule before today - ServiceResult result_2 = taskScheduleService.scheduleBasic(entityManager.find(Task.class, 1L), new BasicScheduleFieldInfo(LocalDate.of(2010, 3, 14))); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode()); - - //Situation 3: Valid schedule - ServiceResult result_3 = taskScheduleService.scheduleBasic(entityManager.find(Task.class, 1L), new BasicScheduleFieldInfo(LocalDate.now())); - assertEquals(ServiceExitCode.OK, result_3.getExitCode()); - assertThat(entityManager.find(BasicTaskSchedule.class, result_3.getResult().getScheduleID())).isNotNull(); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void editBasicSchedule() { - //Situation 1: Reschedule finished task - ServiceResult result_1 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 2L), new BasicScheduleFieldInfo(LocalDate.now())); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode()); - - //Situation 2: Reschedule unfinished task with invalid reschedule date - ServiceResult result_2 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 1L), new BasicScheduleFieldInfo(LocalDate.of(2011, 3, 4))); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode()); - - //Situation 3: Reschedule unfinished task with valid reschedule date - LocalDate oldDate = entityManager.find(BasicTaskSchedule.class, 1L).getScheduleDate(); - ServiceResult result_3 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 1L), new BasicScheduleFieldInfo(LocalDate.now())); - assertEquals(ServiceExitCode.OK, result_3.getExitCode()); - assertNotEquals(((BasicTaskSchedule) result_3.getResult()).getScheduleDate(), oldDate); - - //Situation 4: Reschedule already running schedule - ServiceResult result_4 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 4L), - new BasicScheduleFieldInfo(LocalDate.now())); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_4.getExitCode()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void deleteSchedule() { - for(long i=1; i<=2; i++) { - taskScheduleService.deleteSchedule(entityManager.find(BasicTaskSchedule.class, i)); - assertThat(entityManager.find(BasicTaskSchedule.class, i)).isNull(); - } - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void getFilteredScheduledOfUser() { - //Invalid user - assertEquals(0, taskScheduleService.getFilteredScheduledOfUser(LocalDate.now(), false, "Quatsch").size()); - assertEquals(0, taskScheduleService.getFilteredScheduledOfUser(LocalDate.now(), true, "Quatsch").size()); - - //User with no tasks/schedules - assertEquals(0, taskScheduleService.getFilteredScheduledOfUser(LocalDate.now(), false, username2).size()); - assertEquals(0, taskScheduleService.getFilteredScheduledOfUser(LocalDate.now(), true, username2).size()); - - //user with tasks and schedules - List result_1 = taskScheduleService.getFilteredScheduledOfUser(LocalDate.of(2024,11,11), false, username); - assertEquals(3, result_1.size()); - assertTrue(result_1.contains(entityManager.find(BasicTaskSchedule.class, 3L))); - assertTrue(result_1.contains(entityManager.find(BasicTaskSchedule.class, 4L))); - assertTrue(result_1.contains(entityManager.find(BasicTaskSchedule.class, 5L))); - - List result_2 = taskScheduleService.getFilteredScheduledOfUser(LocalDate.of(2024,11,11), true, username); - assertEquals(1, result_2.size()); - } - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void scheduleNow() { - //Situation 1: Task has already an active schedule - ServiceResult result_1 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 3L)); - assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, result_1.getExitCode()); - - //Situation 2: Task is already finished - ServiceResult result_2 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 2L)); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode()); - - //Situation 3: Task can be scheduled and started - ServiceResult result_3 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 5L)); - assertEquals(ServiceExitCode.OK, result_3.getExitCode()); - assertThat(entityManager.find(BasicTaskSchedule.class, result_3.getResult().getScheduleID())).isNotNull(); - - //Situation 4: Running Advanced Schedule - ServiceResult result_4 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 17L)); - assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, result_4.getExitCode()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void activateSchedule() { - //Activate already running schedule - ServiceResult result_1 = taskScheduleService.activateSchedule(entityManager.find(BasicTaskSchedule.class, 4L)); - assertNotNull(result_1.getResult().getStartTime()); - assertNull(result_1.getResult().getStopTime()); - - entityManager.remove(entityManager.find(BasicTaskSchedule.class, 4L)); - assertThat(entityManager.find(BasicTaskSchedule.class, 4L)).isNull(); - - //Activate not running schedule - ServiceResult result_2 = taskScheduleService.activateSchedule(entityManager.find(BasicTaskSchedule.class, 5L)); - assertNotNull(result_2.getResult().getStartTime()); - assertNull(result_2.getResult().getStopTime()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void stopSchedule() { - //Stop schedule that is not running 4 - ServiceResult result_1 = taskScheduleService.stopSchedule(entityManager.find(BasicTaskSchedule.class, 5L), false); - assertNull(result_1.getResult().getStartTime()); - assertNull(result_1.getResult().getStopTime()); - - //Stop schedule (without finishing) - ServiceResult result_2 = taskScheduleService.stopSchedule(entityManager.find(BasicTaskSchedule.class, 4L), false); - assertNotNull(result_2.getResult().getStartTime()); - assertNotNull(result_2.getResult().getStopTime()); - - //Stop schedule with finishing - ServiceResult result_3 = taskScheduleService.stopSchedule(entityManager.find(BasicTaskSchedule.class, 7L), true); - assertNotNull(result_3.getResult().getStartTime()); - assertNotNull(result_3.getResult().getStopTime()); - assertTrue(result_3.getResult().getTask().isFinished()); - assertFalse(result_3.getResult().isStartable()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void registerForgottenSchedule() { - //Register task schedule for task that is already finished - LocalDateTime startTime = LocalDateTime.now().minusMinutes(10L); - LocalDateTime finishTime = LocalDateTime.now(); - - ServiceResult result_1 = taskScheduleService.registerForgottenSchedule(entityManager.find(Task.class, 2L), new ForgottenScheduleInfo(startTime, finishTime)); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode()); - - ServiceResult result_2 = taskScheduleService.registerForgottenSchedule(entityManager.find(Task.class, 5L), new ForgottenScheduleInfo(startTime, finishTime)); - assertEquals(ServiceExitCode.OK, result_2.getExitCode()); - assertEquals(startTime, result_2.getResult().getStartTime()); - assertEquals(finishTime, result_2.getResult().getStopTime()); - assertThat(entityManager.find(BasicTaskSchedule.class, result_2.getResult().getScheduleID())).isNotNull(); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void getAllMissedSchedulesOfUser() { - assertEquals(1, taskScheduleService.getAllMissedSchedulesOfUser(username).size()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void scheduleAdvanced() { - //Situation 1: Schedule finished Task - ServiceResult result_1 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 18L), - new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(1L), LocalDateTime.now().plusHours(2L))); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode()); - - //Situation 2: Schedule Start is before today - ServiceResult result_2 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L), - new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(1L), LocalDateTime.now().plusHours(2L))); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode()); - - //Situation 3: Schedule End is before today - ServiceResult result_3 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L), - new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(2L), LocalDateTime.now().minusDays(1L))); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_3.getExitCode()); - - //Situation 4: Start after stop - ServiceResult result_4 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L), - new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(2L), LocalDateTime.now().plusHours(1L))); - assertEquals(ServiceExitCode.INVALID_PARAMETER, result_4.getExitCode()); - - //Situation 5: Valid schedule - ServiceResult result_5 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L), - new AdvancedScheduleFieldInfo(LocalDateTime.now(), LocalDateTime.now().plusHours(1L))); - assertEquals(ServiceExitCode.OK, result_5.getExitCode()); - assertThat(entityManager.find(AdvancedTaskSchedule.class, result_5.getResult().getScheduleID())).isNotNull(); - - - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void editscheduleAdvanced() { - //Situation 1: Schedule finished Task - ServiceResult result_1 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 12L), - new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(1L), LocalDateTime.now().plusHours(2L))); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode()); - - //Situation 2: Schedule Start is before today - ServiceResult result_2 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L), - new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(1L), LocalDateTime.now().plusHours(2L))); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode()); - - //Situation 3: Schedule End is before today - ServiceResult result_3 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L), - new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(2L), LocalDateTime.now().minusDays(1L))); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_3.getExitCode()); - - //Situation 4: Start after stop - ServiceResult result_4 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L), - new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(2L), LocalDateTime.now().plusHours(1L))); - assertEquals(ServiceExitCode.INVALID_PARAMETER, result_4.getExitCode()); - - //Situation 5: Valid schedule - ServiceResult result_5 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L), - new AdvancedScheduleFieldInfo(LocalDateTime.now(), LocalDateTime.now().plusHours(1L))); - assertEquals(ServiceExitCode.OK, result_5.getExitCode()); - assertThat(entityManager.find(AdvancedTaskSchedule.class, result_5.getResult().getScheduleID())).isNotNull(); - - //Situation 6: reschedule already running schedule - ServiceResult result_6 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 9L), - new AdvancedScheduleFieldInfo(LocalDateTime.now(), LocalDateTime.now().plusHours(1L))); - assertEquals(ServiceExitCode.INVALID_OPERATION, result_6.getExitCode()); - } -} diff --git a/backend/src/test/java/core/taskgroups/TaskgroupRepsitoryTest.java b/backend/src/test/java/core/taskgroups/TaskgroupRepsitoryTest.java deleted file mode 100644 index 9a80085..0000000 --- a/backend/src/test/java/core/taskgroups/TaskgroupRepsitoryTest.java +++ /dev/null @@ -1,93 +0,0 @@ -package core.taskgroups; - -import core.entities.User; -import core.entities.timemanager.Task; -import core.entities.timemanager.Taskgroup; -import core.repositories.timemanager.TaskgroupRepository; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import java.util.List; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.*; - -@ExtendWith(SpringExtension.class) -@DataJpaTest -public class TaskgroupRepsitoryTest { - - @Autowired private TaskgroupRepository taskgroupRepository; - @Autowired private TestEntityManager testEntityManager; - - @Test - @Sql("classpath:taskgroupRepositoryTestEntries.sql") - void findAllByUser() { - User testUser1 = testEntityManager.find(User.class, 1L); - User testUser2 = testEntityManager.find(User.class, 2L); - - List result_user2 = taskgroupRepository.findAllByUser(testUser2.getUsername()); - assertEquals(0, result_user2.size()); - - List result_user1 = taskgroupRepository.findAllByUser(testUser1.getUsername()); - assertEquals(8, result_user1.size()); - } - - @Test - @Sql("classpath:taskgroupRepositoryTestEntries.sql") - void findAllTopTaskgroupsByUser() { - User testUser1 = testEntityManager.find(User.class, 1L); - User testUser2 = testEntityManager.find(User.class, 2L); - - //Situation 1: Empty user, no taskgroups - assertEquals(0, taskgroupRepository.findAllTopTaskgroupsByUser(testUser2.getUsername()).size()); - - //Situation 2: Only top taskgroups are returned - List topgroups_user1 = taskgroupRepository.findAllTopTaskgroupsByUser(testUser1.getUsername()); - assertEquals(3, topgroups_user1.size()); - assertTrue(topgroups_user1.contains(testEntityManager.find(Taskgroup.class, 1L))); - assertTrue(topgroups_user1.contains(testEntityManager.find(Taskgroup.class, 2L))); - assertTrue(topgroups_user1.contains(testEntityManager.find(Taskgroup.class, 5L))); - - //Situation 3: User with username does not exist - assertEquals(0, taskgroupRepository.findAllTopTaskgroupsByUser("Rotzbakke").size()); - } - @Test - @Sql("classpath:taskgroupRepositoryTestEntries.sql") - void deleteAllByUser() { - User testUser1 = testEntityManager.find(User.class, 1L); - User testUser2 = testEntityManager.find(User.class, 2L); - - taskgroupRepository.deleteAllByUser(testUser2); - for(long i=1; i<=8; i++) { - assertThat(testEntityManager.find(Taskgroup.class, i)).isNotNull(); - } - - taskgroupRepository.deleteAllByUser(testUser1); - for(long i=1; i<=8; i++) { - assertThat(testEntityManager.find(Taskgroup.class, i)).isNull(); - } - } - - @Test - @Sql("classpath:taskgroupRepositoryTestEntries.sql") - void delete() { - Taskgroup no_children = testEntityManager.find(Taskgroup.class, 1L); - Taskgroup taskgroup_with_children = testEntityManager.find(Taskgroup.class, 5L); - - taskgroupRepository.delete(no_children); - assertThat(testEntityManager.find(Taskgroup.class, 1L)).isNull(); - for(long i=2; i<=8; i++) { - assertThat(testEntityManager.find(Taskgroup.class, i)).isNotNull(); - } - - taskgroupRepository.delete(taskgroup_with_children); - for(long i=5; i<=8; i++) { - assertThat(testEntityManager.find(Taskgroup.class, i)).isNull(); - } - } -} diff --git a/backend/src/test/java/core/taskgroups/TaskgroupServiceTest.java b/backend/src/test/java/core/taskgroups/TaskgroupServiceTest.java deleted file mode 100644 index eef487c..0000000 --- a/backend/src/test/java/core/taskgroups/TaskgroupServiceTest.java +++ /dev/null @@ -1,202 +0,0 @@ -package core.taskgroups; - -import core.api.models.timemanager.taskgroup.TaskgroupFieldInfo; -import core.entities.User; -import core.entities.timemanager.Task; -import core.entities.timemanager.Taskgroup; -import core.repositories.UserRepository; -import core.repositories.timemanager.TaskgroupRepository; -import core.services.PermissionResult; -import core.services.ServiceExitCode; -import core.services.ServiceResult; -import core.services.TaskgroupService; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.SqlGroup; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.context.junit4.SpringRunner; - -import javax.persistence.EntityManager; -import javax.transaction.Transactional; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Optional; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.*; - -@SpringBootTest -@Transactional -public class TaskgroupServiceTest { - - @Autowired - private TaskgroupRepository taskgroupRepository; - @Autowired - private TaskgroupService taskgroupService; - @Autowired - private EntityManager entityManager; - - private static final String username = "Testuser1"; - private static final String username2 = "Testuser2"; - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void getTaskgroupByIDAndUsername() { - //Situation 1: correct taskgroup and username - assertFalse(taskgroupRepository.findById(1L).isEmpty()); - - PermissionResult permissionResult = taskgroupService.getTaskgroupByIDAndUsername(1L, username); - assertThat(permissionResult).isNotNull(); - assertTrue(permissionResult.isHasPermissions()); - assertEquals(ServiceExitCode.OK, permissionResult.getExitCode()); - assertEquals(taskgroupRepository.findById(1L).get(), permissionResult.getResult()); - - //Situation 2: invalid taskgroup - PermissionResult invalid_group = taskgroupService.getTaskgroupByIDAndUsername(-1L, username); - assertThat(invalid_group).isNotNull(); - assertEquals(ServiceExitCode.MISSING_ENTITY, invalid_group.getExitCode()); - assertFalse(invalid_group.isHasPermissions()); - - //Situation 3: invalid user - PermissionResult invalid_user = taskgroupService.getTaskgroupByIDAndUsername(1L, "Rotzbakke"); - assertThat(invalid_user).isNotNull(); - assertEquals(ServiceExitCode.OK, invalid_user.getExitCode()); - assertFalse(invalid_user.isHasPermissions()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void addTaskgroup() { - TaskgroupFieldInfo taskgroupFieldInfo = new TaskgroupFieldInfo("Taskgroup", -1); - //Situation 1: No such user - assertThrows(NoSuchElementException.class, () -> taskgroupService.addTaskgroup(taskgroupFieldInfo, "Rotzbakke")); - - //Situation 2: Taskgroup already exists - Taskgroup taskgroup = taskgroupRepository.findById(1L).get(); - ServiceResult creationResult = taskgroupService.addTaskgroup(new TaskgroupFieldInfo(taskgroup.getTaskgroupName(), -1), username); - assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, creationResult.getExitCode()); - assertThat(creationResult.getResult()).isNull(); - - //Situation 3: Taskgroup does not exist, no parent - ServiceResult creationResult_3 = taskgroupService.addTaskgroup(taskgroupFieldInfo, username); - assertEquals(ServiceExitCode.OK, creationResult_3.getExitCode()); - assertTrue(taskgroupRepository.existsById(creationResult_3.getResult().getTaskgroupID())); - - //Situation 4: Taskgroup does not exist, with parent; invalid parent (no existent) - ServiceResult creationResult_4 = taskgroupService.addTaskgroup(new TaskgroupFieldInfo("Situation 4", 100L), username); - assertEquals(ServiceExitCode.MISSING_ENTITY, creationResult_4.getExitCode()); - - //Situation 5: Taskgroup does not exist, parent exist - ServiceResult creationResult_5 = taskgroupService.addTaskgroup(new TaskgroupFieldInfo("Situation 5", 2L), username); - assertEquals(ServiceExitCode.OK, creationResult_5.getExitCode()); - assertTrue(taskgroupRepository.existsById(creationResult_5.getResult().getTaskgroupID())); - - //Situation 6: taskgroup exist on another user - ServiceResult creationResult_6 = taskgroupService.addTaskgroup(new TaskgroupFieldInfo(taskgroup.getTaskgroupName(), -1), username2); - assertEquals(ServiceExitCode.OK, creationResult_6.getExitCode()); - assertTrue(taskgroupRepository.existsById(creationResult_6.getResult().getTaskgroupID())); - - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void editTaskgroup() { - Taskgroup taskgroup = taskgroupRepository.findById(1L).get(); - //Situation 1: Nothing changed - ServiceExitCode exitCode_1 = taskgroupService.editTaskgroup(taskgroup, new TaskgroupFieldInfo(taskgroup.getTaskgroupName(),-1)); - assertEquals(ServiceExitCode.OK, exitCode_1); - - //Situation 2: Name is already taken - ServiceExitCode exitCode_2 = taskgroupService.editTaskgroup(taskgroup, new TaskgroupFieldInfo("Taskgroup 1", -1)); - assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, exitCode_2); - - //Situation 3: All fine - ServiceExitCode exitCode_3 = taskgroupService.editTaskgroup(taskgroup, new TaskgroupFieldInfo("Situation 3", -1)); - assertEquals(ServiceExitCode.OK, exitCode_3); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void deleteTaskgroup() { - taskgroupService.deleteTaskgroup(entityManager.find(Taskgroup.class, 1L)); - assertThat(entityManager.find(Taskgroup.class, 1L)).isNull(); - - taskgroupService.deleteTaskgroup(entityManager.find(Taskgroup.class, 2L)); - assertThat(entityManager.find(Taskgroup.class, 2L)).isNull(); - assertThat(entityManager.find(Taskgroup.class, 3L)).isNull(); - for(long i=1; i<=14; i++) { - assertThat(entityManager.find(Task.class, i)).isNull(); - } - - taskgroupService.deleteTaskgroup(entityManager.find(Taskgroup.class, 5L)); - assertThat(entityManager.find(Taskgroup.class, 5L)).isNull(); - assertThat(entityManager.find(Taskgroup.class, 6L)).isNull(); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void getTopTaskgroupsByUser() { - //Situation 1: User without taskgroups - List taskgroups_user2 = taskgroupService.getTopTaskgroupsByUser(username2); - assertEquals(0, taskgroups_user2.size()); - - - //Situation 2: user with taskgroups - List taskgroups_user1 = taskgroupService.getTopTaskgroupsByUser(username); - assertEquals(3, taskgroups_user1.size()); - assertTrue(taskgroups_user1.contains(entityManager.find(Taskgroup.class, 1L))); - assertTrue(taskgroups_user1.contains(entityManager.find(Taskgroup.class, 2L))); - assertTrue(taskgroups_user1.contains(entityManager.find(Taskgroup.class, 5L))); - - //Situation 3: No existent username - assertEquals(0, taskgroupService.getTopTaskgroupsByUser("Rotzbakke").size()); - } - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void deleteTaskgroupByUser() { - User referenceUser1 = entityManager.find(User.class, 1L); - User referenceUser2 = entityManager.find(User.class, 2L); - - taskgroupService.deleteTaskgroupByUser(referenceUser2); - for(long i=1; i<=8; i++) { - assertThat(entityManager.find(Taskgroup.class, i)).isNotNull(); - } - - taskgroupService.deleteTaskgroupByUser(referenceUser1); - for(long i=1; i<=8; i++) { - assertThat(entityManager.find(Taskgroup.class, i)).isNull(); - } - for(long i=1; i<=14; i++) { - assertThat(entityManager.find(Task.class, i)).isNull(); - } - } - -} diff --git a/backend/src/test/java/core/tasks/TaskRepositoryTest.java b/backend/src/test/java/core/tasks/TaskRepositoryTest.java deleted file mode 100644 index 99ea0ce..0000000 --- a/backend/src/test/java/core/tasks/TaskRepositoryTest.java +++ /dev/null @@ -1,160 +0,0 @@ -package core.tasks; - -import core.entities.User; -import core.entities.timemanager.Task; -import core.entities.timemanager.Taskgroup; -import core.repositories.timemanager.TaskRepository; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.SqlGroup; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import java.time.LocalDate; -import java.util.List; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - - -@ExtendWith(SpringExtension.class) -@DataJpaTest -public class TaskRepositoryTest { - - @Autowired private TaskRepository taskRepository; - @Autowired private TestEntityManager testEntityManager; - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void findAllByUser() { - User testUser1 = testEntityManager.find(User.class, 1L); - User testUser2 = testEntityManager.find(User.class, 2L); - - //Situation 1: Non existent user - assertEquals(0, taskRepository.findAllByUser("Rotzbakke", true).size()); - assertEquals(0, taskRepository.findAllByUser("Rotzbakke", false).size()); - - //Situation 2: User with no tasks at all - assertEquals(0, taskRepository.findAllByUser(testUser2.getUsername(), false).size()); - assertEquals(0, taskRepository.findAllByUser(testUser2.getUsername(), true).size()); - - //Situation 3: User with finished and unfinished tasks - List tasks_user1_false = taskRepository.findAllByUser(testUser1.getUsername(), false); - List tasks_user1_true = taskRepository.findAllByUser(testUser1.getUsername(), true); - assertEquals(7, tasks_user1_true.size()); - assertEquals(8, tasks_user1_false.size()); - - assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 1L))); - assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 3L))); - assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 5L))); - assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 7L))); - assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 9L))); - assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 11L))); - assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 12L))); - - assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 2L))); - assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 4L))); - assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 6L))); - assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 8L))); - assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 10L))); - assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 13L))); - assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 14L))); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void deleteAllByTaskgroup() { - Taskgroup taskgroup_no_tasks = testEntityManager.find(Taskgroup.class, 1L); - taskRepository.deleteAllByTaskgroup(taskgroup_no_tasks); - - for(long i=1; i<=14; i++) { - assertThat(testEntityManager.find(Task.class, i)).isNotNull(); - } - - Taskgroup taskgroup_with_task = testEntityManager.find(Taskgroup.class, 2L); - taskRepository.deleteAllByTaskgroup(taskgroup_with_task); - for(long i=1; i<=14; i++) { - Task task = testEntityManager.find(Task.class, i); - assertThat(task).isNull(); - } - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void deleteByTaskID() { - taskRepository.deleteByTaskID(-1); - for(long i=1; i<=14; i++) { - assertThat(testEntityManager.find(Task.class, i)).isNotNull(); - } - - taskRepository.deleteByTaskID(1); - assertThat(testEntityManager.find(Task.class, 1L)).isNull(); - for(long i=2; i<=14; i++) { - assertThat(testEntityManager.find(Task.class, i)).isNotNull(); - } - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void findAllOverdue() { - User testuser1 = testEntityManager.find(User.class, 1L); - LocalDate referenceDate = LocalDate.of(2023, 10, 11); - - List overdue = taskRepository.findAllOverdue(testuser1.getUsername(), referenceDate); - assertEquals(2, overdue.size()); - assertTrue(overdue.contains(testEntityManager.find(Task.class, 3L))); - assertTrue(overdue.contains(testEntityManager.find(Task.class, 5L))); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void findAllUpcoming() { - User testuser1 = testEntityManager.find(User.class, 1L); - LocalDate referenceDate = LocalDate.of(2023, 10, 11); - - List upcoming = taskRepository.findAllUpcoming(testuser1.getUsername(), referenceDate); - assertEquals(2, upcoming.size()); - assertTrue(upcoming.contains(testEntityManager.find(Task.class, 7L))); - assertTrue(upcoming.contains(testEntityManager.find(Task.class, 9L))); - - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") - }) - void findAllActive() { - User testuser1 = testEntityManager.find(User.class, 1L); - LocalDate referenceDate = LocalDate.of(2023, 10, 11); - - List active = taskRepository.findAllActive(testuser1.getUsername(), referenceDate); - //1,3,5,11,12 - assertEquals(6, active.size()); - assertTrue(active.contains(testEntityManager.find(Task.class, 1L))); - assertTrue(active.contains(testEntityManager.find(Task.class, 3L))); - assertTrue(active.contains(testEntityManager.find(Task.class, 5L))); - assertTrue(active.contains(testEntityManager.find(Task.class, 11L))); - assertTrue(active.contains(testEntityManager.find(Task.class, 12L))); - } - -} diff --git a/backend/src/test/java/core/tasks/TaskServiceTest.java b/backend/src/test/java/core/tasks/TaskServiceTest.java deleted file mode 100644 index ede0e93..0000000 --- a/backend/src/test/java/core/tasks/TaskServiceTest.java +++ /dev/null @@ -1,287 +0,0 @@ -package core.tasks; - -import core.api.models.timemanager.tasks.TaskFieldInfo; -import core.api.models.timemanager.tasks.TaskScope; -import core.entities.timemanager.BasicTaskSchedule; -import core.entities.timemanager.Task; -import core.entities.timemanager.Taskgroup; -import core.repositories.timemanager.TaskRepository; -import core.repositories.timemanager.TaskgroupRepository; -import core.services.*; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.Rollback; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.SqlGroup; - -import javax.persistence.EntityManager; -import javax.transaction.Transactional; - -import java.time.LocalDate; -import java.util.List; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.*; - -@SpringBootTest -@Transactional -public class TaskServiceTest { - - - @Autowired - private TaskService taskService; - @Autowired - private EntityManager entityManager; - - private static final String username = "Testuser1"; - private static final String username2 = "Testuser2"; - @Autowired - private TaskRepository taskRepository; - @Autowired - private TaskgroupRepository taskgroupRepository; - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void createTask() { - //Situation 1: Task with that name already exists in a taskgroup - TaskFieldInfo taskFieldInfo_1 = new TaskFieldInfo(entityManager.find(Task.class, 1L).getTaskName(), 0, null, null); - ServiceResult situation_1 = taskService.createTask(entityManager.find(Taskgroup.class, 2L), taskFieldInfo_1); - assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, situation_1.getExitCode()); - - //Situation 2: Task with that name exists in another taskgroup - TaskFieldInfo taskFieldInfo_2 = new TaskFieldInfo(entityManager.find(Task.class, 1L).getTaskName(), 0, null, null); - ServiceResult result_2 = taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_2); - assertEquals(ServiceExitCode.OK, result_2.getExitCode()); - assertThat(entityManager.find(Task.class, result_2.getResult().getTaskID())).isNotNull(); - - //Situation 3: Normal, everything fine - TaskFieldInfo taskFieldInfo_3 = new TaskFieldInfo("Situation 3", 0, null, null); - ServiceResult result_3 = taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_3); - assertEquals(ServiceExitCode.OK, result_3.getExitCode()); - assertThat(entityManager.find(Task.class, result_3.getResult().getTaskID())).isNotNull(); - - //Robustness - Test for invalid dates - //Situation 4: Deadline, no start - TaskFieldInfo taskFieldInfo_4 = new TaskFieldInfo("Situation 4", 0, null, LocalDate.now()); - ServiceResult result_4 = taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_4); - assertEquals(ServiceExitCode.OK, result_4.getExitCode()); - assertThat(entityManager.find(Task.class, result_4.getResult().getTaskID())).isNotNull(); - - //Situation 5: Start but no deadline - TaskFieldInfo taskFieldInfo_5 = new TaskFieldInfo("Situation 5", 0, LocalDate.now(),null); - ServiceResult result_5 = taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_5); - assertEquals(ServiceExitCode.OK, result_5.getExitCode()); - assertThat(entityManager.find(Task.class, result_5.getResult().getTaskID())).isNotNull(); - - //Situation 6: Deadline before start (invalid) - TaskFieldInfo taskFieldInfo_6 = new TaskFieldInfo("Situation 6", 0, LocalDate.now(),LocalDate.of(2010, 3, 20)); - ServiceResult result_6= taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_6); - assertEquals(ServiceExitCode.INVALID_PARAMETER, result_6.getExitCode()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void getTaskPermissions() { - //Situation 1: correct task and username - PermissionResult permissionResult_1 = taskService.getTaskPermissions(1L, username); - assertEquals(ServiceExitCode.OK, permissionResult_1.getExitCode()); - assertTrue(permissionResult_1.isHasPermissions()); - assertEquals(entityManager.find(Task.class, 1L), permissionResult_1.getResult()); - - //Situation 2: invalid taskgroup - PermissionResult permissionResult_2 = taskService.getTaskPermissions(200L, username); - assertEquals(ServiceExitCode.MISSING_ENTITY, permissionResult_2.getExitCode()); - assertFalse(permissionResult_2.isHasPermissions()); - assertThat(permissionResult_2.getResult()).isNull(); - - //Situation 3: invalid user - PermissionResult permissionResult_3 = taskService.getTaskPermissions(1L, username2); - assertEquals(ServiceExitCode.OK, permissionResult_3.getExitCode()); - assertFalse(permissionResult_2.isHasPermissions()); - assertEquals(entityManager.find(Task.class, 1L), permissionResult_3.getResult()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void editTask() { - //Situation 1: Nothing is updated - Task task_1 = entityManager.find(Task.class, 1L); - TaskFieldInfo taskFieldInfo_1 = new TaskFieldInfo(entityManager.find(Task.class, 1L).getTaskName(), 0, null, null); - ServiceResult result_1 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_1); - assertEquals(ServiceExitCode.OK, result_1.getExitCode()); - assertEquals(task_1, result_1.getResult()); - - //Situation 2: Name is updated to name that already exists within the taskgroup - Task task_2 = entityManager.find(Task.class, 1L); - TaskFieldInfo taskFieldInfo_2 = new TaskFieldInfo(entityManager.find(Task.class, 2L).getTaskName(), 0, null, null); - ServiceResult result_2 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_2); - task_2.setTaskName(entityManager.find(Task.class, 2L).getTaskName()); - assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, result_2.getExitCode()); - assertNotEquals(task_2, result_2.getResult()); - - //Situation 3: Name is updated to nonexistend Name - Task task_3 = entityManager.find(Task.class, 1L); - TaskFieldInfo taskFieldInfo_3 = new TaskFieldInfo("Situation 3", 0, null, null); - ServiceResult result_3 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_3); - task_3.setTaskName("Situation 3"); - assertEquals(ServiceExitCode.OK, result_3.getExitCode()); - assertEquals(task_3, result_3.getResult()); - - //Situation 4: eta is updated - Task task_4 = entityManager.find(Task.class, 1L); - TaskFieldInfo taskFieldInfo_4 = new TaskFieldInfo(task_4.getTaskName(), 90, null, null); - ServiceResult result_4 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_4); - task_4.setEta(90); - assertEquals(ServiceExitCode.OK, result_4.getExitCode()); - assertEquals(task_4, result_4.getResult()); - - //Situation 5: deadline and start is updated in a valid way - Task task_5 = entityManager.find(Task.class, 1L); - TaskFieldInfo taskFieldInfo_5 = new TaskFieldInfo(task_5.getTaskName(), task_5.getEta(), LocalDate.of(2023, 4, 9), LocalDate.of(2023,5,9)); - ServiceResult result_5 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_5); - task_5.setStartDate(LocalDate.of(2023,4,9)); - task_5.setDeadline(LocalDate.of(2023,5,9)); - assertEquals(ServiceExitCode.OK, result_5.getExitCode()); - assertEquals(task_5, result_5.getResult()); - - //Situation 6: Deadline and start are updated in a not valid way - Task task_6 = entityManager.find(Task.class, 1L); - TaskFieldInfo taskFieldInfo_6 = new TaskFieldInfo(task_5.getTaskName(), task_5.getEta(), LocalDate.of(2023, 5, 9), LocalDate.of(2023,4,9)); - ServiceResult result_6 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_6); - task_6.setStartDate(LocalDate.of(2023,5,9)); - task_6.setDeadline(LocalDate.of(2023,4,9)); - assertEquals(ServiceExitCode.INVALID_PARAMETER, result_6.getExitCode()); - assertNotEquals(task_6, result_6.getResult()); - - //Situation 10 Startdate = null; - Task task_10 = entityManager.find(Task.class, 5L); - TaskFieldInfo taskFieldInfo_10 = new TaskFieldInfo(task_10.getTaskName(), task_10.getEta(),null, task_10.getDeadline()); - ServiceResult result_10 = taskService.editTask(entityManager.find(Task.class, 5L), taskFieldInfo_10); - task_10.setStartDate(null); - assertEquals(ServiceExitCode.OK, result_10.getExitCode()); - assertEquals(task_10, result_10.getResult()); - - //Situation 11 Deadline = null - Task task_11 = entityManager.find(Task.class, 5L); - TaskFieldInfo taskFieldInfo_11 = new TaskFieldInfo(task_11.getTaskName(), task_11.getEta(),task_11.getStartDate(), null); - ServiceResult result_11 = taskService.editTask(entityManager.find(Task.class, 5L), taskFieldInfo_11); - task_11.setDeadline(null); - assertEquals(ServiceExitCode.OK, result_11.getExitCode()); - assertEquals(task_11, result_11.getResult()); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void deleteTask() { - for(long i=1; i<=15; i++) { - taskService.deleteTask(entityManager.find(Task.class, i)); - assertThat(entityManager.find(Task.class, i)).isNull(); - } - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void clearTasks() { - //Situation 1: Delete from taskgroup with no tasks - taskService.clearTasks(entityManager.find(Taskgroup.class, 1L)); - for(long i=1; i<=15; i++) { - assertThat(entityManager.find(Task.class, i)).isNotNull(); - } - //Situation 2: Delete from taskgroup with tasks - taskService.clearTasks(entityManager.find(Taskgroup.class, 2L)); - for(long i=1; i<=15; i++) { - assertThat(entityManager.find(Task.class, i)).isNull(); - } - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void finishTask() { - taskService.finishTask(entityManager.find(Task.class, 1L)); - assertTrue(entityManager.find(Task.class, 1L).isFinished()); - - taskService.finishTask(entityManager.find(Task.class, 2L)); - assertTrue(entityManager.find(Task.class, 1L).isFinished()); - assertThat(entityManager.find(BasicTaskSchedule.class, 2L)).isNull(); - } - - @Test - @SqlGroup({ - @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql"), - @Sql("classpath:basicScheduleEntries.sql") - }) - void loadAllTasks() { - //Situation 1: No tasks existing - List result_1 = taskService.loadAllTasks(username2, TaskScope.UNFINISHED); - assertEquals(0, result_1.size()); - - //Situation 2: Tasks existing, Unfinished# - List result_2 = taskService.loadAllTasks(username, TaskScope.UNFINISHED); - assertEquals(8, result_2.size()); - assertTrue(result_2.contains(entityManager.find(Task.class, 1L))); - assertTrue(result_2.contains(entityManager.find(Task.class, 3L))); - assertTrue(result_2.contains(entityManager.find(Task.class, 5L))); - assertTrue(result_2.contains(entityManager.find(Task.class, 7L))); - assertTrue(result_2.contains(entityManager.find(Task.class, 9L))); - assertTrue(result_2.contains(entityManager.find(Task.class, 11L))); - assertTrue(result_2.contains(entityManager.find(Task.class, 12L))); - - //Situation 3: Finished tasks - List result_3 = taskService.loadAllTasks(username, TaskScope.FINISHED); - assertEquals(7, result_3.size()); - assertTrue(result_3.contains(entityManager.find(Task.class, 2L))); - assertTrue(result_3.contains(entityManager.find(Task.class, 4L))); - assertTrue(result_3.contains(entityManager.find(Task.class, 6L))); - assertTrue(result_3.contains(entityManager.find(Task.class, 8L))); - assertTrue(result_3.contains(entityManager.find(Task.class, 10L))); - assertTrue(result_3.contains(entityManager.find(Task.class, 13L))); - assertTrue(result_3.contains(entityManager.find(Task.class, 14L))); - - //overdue - List result_4 = taskService.loadAllTasks(username, TaskScope.OVERDUE); - assertEquals(2, result_4.size()); - assertTrue(result_4.contains(entityManager.find(Task.class, 3L))); - assertTrue(result_4.contains(entityManager.find(Task.class, 5L))); - - //upcoming - List result_5 = taskService.loadAllTasks(username, TaskScope.UPCOMING); - assertEquals(2, result_5.size()); - assertTrue(result_5.contains(entityManager.find(Task.class, 7L))); - assertTrue(result_5.contains(entityManager.find(Task.class, 9L))); - //Active - List result_6 = taskService.loadAllTasks(username, TaskScope.ACTIVE); - assertEquals(6, result_6.size()); - assertTrue(result_6.contains(entityManager.find(Task.class, 1L))); - assertTrue(result_6.contains(entityManager.find(Task.class, 3L))); - assertTrue(result_6.contains(entityManager.find(Task.class, 5L))); - assertTrue(result_6.contains(entityManager.find(Task.class, 11L))); - assertTrue(result_6.contains(entityManager.find(Task.class, 12L))); - - } -} diff --git a/backend/src/test/java/core/users/UserRepositoryTests.java b/backend/src/test/java/core/users/UserRepositoryTests.java deleted file mode 100644 index 0b19155..0000000 --- a/backend/src/test/java/core/users/UserRepositoryTests.java +++ /dev/null @@ -1,87 +0,0 @@ -package core.users; - -import core.entities.User; -import core.repositories.UserRepository; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import java.util.Optional; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.*; - -@DataJpaTest -@ExtendWith(SpringExtension.class) -public class UserRepositoryTests { - - @Autowired - private UserRepository userRepository; - - @Autowired - private TestEntityManager testEntityManager; - - @Test - @Sql("classpath:userRepisotoryTestEntries.sql") - void test_findByUsername() { - //Situation 1: User with name "FawKes100" is present - User referenceUser = testEntityManager.find(User.class, 1L); - Optional findResult = userRepository.findByUsername(referenceUser.getUsername()); - assertTrue(findResult.isPresent()); - assertEquals(referenceUser,findResult.get()); - - //Situation 2: No user with the required name is present - findResult = userRepository.findByUsername("fawkes1001"); - assertFalse(findResult.isPresent()); - } - - @Test - @Sql("classpath:userRepisotoryTestEntries.sql") - void test_existsByMail() { - User referenceUser = testEntityManager.find(User.class, 1L); - //Situation 1: invalid email format should not matter - assertFalse(userRepository.existsByEmail("FawKes100")); - - //Situation 2: No user exists with such a mail - assertFalse(userRepository.existsByEmail("mail@fawkes100.de")); - - //Situation 3: User with this mail exists - assertTrue(userRepository.existsByEmail(referenceUser.getEmail())); - } - - @Test - @Sql("classpath:userRepisotoryTestEntries.sql") - void test_existsByUsername() { - User referenceUser = testEntityManager.find(User.class, 1L); - //Situation 1: No such user - assertFalse(userRepository.existsByUsername("FawKes100")); - - //Situation 3: User with this name exists - assertTrue(userRepository.existsByUsername(referenceUser.getUsername())); - } - - @Test - @Sql("classpath:userRepisotoryTestEntries.sql") - void test_deleteUserByName() { - User referenceUser1 = testEntityManager.find(User.class, 1L); - User referenceUser2 = testEntityManager.find(User.class, 2L); - - userRepository.deleteByUsername(referenceUser2.getUsername()); - - assertThat(testEntityManager.find(User.class, referenceUser2.getId())).isNull(); - assertThat(testEntityManager.find(User.class, referenceUser1.getId())).isNotNull(); - } - - - @Test - @Sql("classpath:userRepisotoryTestEntries.sql") - void test_countUsers() { - assertEquals(2, userRepository.countUsers()); - } - -} From f2823ad21e7156182bbc1b008dde6faebbae5d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 12:22:24 +0100 Subject: [PATCH 06/10] Schedule notifcations for all todays schedules and stop notification when schedule is activated --- .../src/main/java/core/DemoApplication.java | 8 +++- backend/src/main/java/core/NotTest.java | 16 -------- .../api/controller/ScheduleController.java | 11 +++++ .../AdvancedScheduleRepository.java | 15 +++++++ .../timemanager/ScheduleRepository.java | 1 + .../core/services/TaskScheduleService.java | 14 +++++++ .../services/ntfy/TaskSchedulingService.java | 41 +++++++++++++++---- 7 files changed, 80 insertions(+), 26 deletions(-) delete mode 100644 backend/src/main/java/core/NotTest.java create mode 100644 backend/src/main/java/core/repositories/timemanager/AdvancedScheduleRepository.java diff --git a/backend/src/main/java/core/DemoApplication.java b/backend/src/main/java/core/DemoApplication.java index 70b701e..6b23158 100644 --- a/backend/src/main/java/core/DemoApplication.java +++ b/backend/src/main/java/core/DemoApplication.java @@ -2,6 +2,7 @@ package core; import core.entities.RoleEntity; import core.entities.UserRole; +import core.entities.timemanager.AdvancedTaskSchedule; import core.repositories.RoleRepository; import core.repositories.UserRepository; import core.services.PropertyService; @@ -14,6 +15,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import org.springframework.scheduling.annotation.EnableScheduling; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + @SpringBootApplication @EnableScheduling public class DemoApplication{ @@ -24,10 +29,9 @@ public class DemoApplication{ @Bean - @NotTest public CommandLineRunner init(TaskSchedulingService taskSchedulingService) { return args -> { - taskSchedulingService.scheduleStartingTask("Finishing ConceptCreator"); + taskSchedulingService.scheduleStartReminders(); }; } diff --git a/backend/src/main/java/core/NotTest.java b/backend/src/main/java/core/NotTest.java deleted file mode 100644 index 871c773..0000000 --- a/backend/src/main/java/core/NotTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package core; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Profile; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - - -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@Profile("!test") -public @interface NotTest { -} diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java index 4fffe8a..dcf1c52 100644 --- a/backend/src/main/java/core/api/controller/ScheduleController.java +++ b/backend/src/main/java/core/api/controller/ScheduleController.java @@ -9,6 +9,8 @@ import core.entities.timemanager.AdvancedTaskSchedule; import core.entities.timemanager.BasicTaskSchedule; import core.entities.timemanager.Task; import core.services.*; +import core.services.ntfy.TaskSchedulingService; +import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.core.context.SecurityContextHolder; @@ -27,6 +29,7 @@ public class ScheduleController { @Autowired private TaskScheduleService taskScheduleService; @Autowired private TaskService taskService; + @Autowired private TaskSchedulingService taskSchedulingService; @GetMapping("/schedules") public ResponseEntity loadAllSchedulesOfUser() { String username = SecurityContextHolder.getContext().getAuthentication().getName(); @@ -198,6 +201,14 @@ public class ScheduleController { } ServiceResult serviceResult = taskScheduleService.activateSchedule(permissionResult.getResult()); + if(serviceResult.getResult() instanceof AdvancedTaskSchedule) { + try { + taskSchedulingService.stopStartReminderNotification((AdvancedTaskSchedule) serviceResult.getResult()); + } catch (SchedulerException e) { + throw new RuntimeException(e); + } + } + return ResponseEntity.ok(new ScheduleActivateResponse(serviceResult.getResult().getStartTime())); } diff --git a/backend/src/main/java/core/repositories/timemanager/AdvancedScheduleRepository.java b/backend/src/main/java/core/repositories/timemanager/AdvancedScheduleRepository.java new file mode 100644 index 0000000..7fbe22f --- /dev/null +++ b/backend/src/main/java/core/repositories/timemanager/AdvancedScheduleRepository.java @@ -0,0 +1,15 @@ +package core.repositories.timemanager; + +import core.entities.timemanager.AdvancedTaskSchedule; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import java.time.LocalDate; +import java.util.List; + +@Repository +public interface AdvancedScheduleRepository extends CrudRepository { + + +} diff --git a/backend/src/main/java/core/repositories/timemanager/ScheduleRepository.java b/backend/src/main/java/core/repositories/timemanager/ScheduleRepository.java index 4486293..df72a88 100644 --- a/backend/src/main/java/core/repositories/timemanager/ScheduleRepository.java +++ b/backend/src/main/java/core/repositories/timemanager/ScheduleRepository.java @@ -19,4 +19,5 @@ public interface ScheduleRepository extends CrudRepository getActiveScheduleOfUser(String username); + } diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index 63491a8..3ee3e70 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -12,6 +12,7 @@ import core.entities.timemanager.AdvancedTaskSchedule; import core.entities.timemanager.BasicTaskSchedule; import core.entities.timemanager.Task; import core.repositories.UserRepository; +import core.repositories.timemanager.AdvancedScheduleRepository; import core.repositories.timemanager.ScheduleRepository; import core.repositories.timemanager.TaskRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -32,6 +33,7 @@ public class TaskScheduleService { @Autowired private UserRepository userRepository; @Autowired private TaskRepository taskRepository; + @Autowired private AdvancedScheduleRepository advancedScheduleRepository; public List getAllSchedulesOfUser(String username) { return scheduleRepository.findAllByUsername(username); @@ -225,6 +227,18 @@ public class TaskScheduleService { return findScheduleByDate(allSchedules, date); } + public List findSchedulesByDate(LocalDate date) { + Iterable allSchedules = advancedScheduleRepository.findAll(); + List schedulesToday = new ArrayList<>(); + for(AdvancedTaskSchedule advancedTaskSchedule : allSchedules) { + if(advancedTaskSchedule.getScheduleStart().toLocalDate().equals(date)) { + schedulesToday.add(advancedTaskSchedule); + } + } + return schedulesToday; + + } + private List findScheduleByDate(List schedules, LocalDate date) { List filteredSchedules = new ArrayList<>(); for(AbstractSchedule schedule : schedules) { diff --git a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java index 5067658..ca34cb9 100644 --- a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java +++ b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java @@ -1,18 +1,25 @@ package core.services.ntfy; -import core.NotTest; +import core.entities.timemanager.AbstractSchedule; +import core.entities.timemanager.AdvancedTaskSchedule; +import core.repositories.timemanager.ScheduleRepository; +import core.repositories.timemanager.TaskRepository; +import core.services.TaskScheduleService; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; +import java.util.List; @Service -@NotTest public class TaskSchedulingService { @Value("${ntfy.host}") @@ -24,19 +31,25 @@ public class TaskSchedulingService { @Value("${frontend.domain}") private String frontend_domain; - public void scheduleStartingTask(String taskName) throws SchedulerException { - Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); + @Autowired private TaskScheduleService taskScheduleService; + + private Scheduler scheduler; + + public void scheduleStartingTask(AdvancedTaskSchedule advancedTaskSchedule) throws SchedulerException { + scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.start(); - JobDetail job = JobBuilder.newJob(NtfyTaskStartNotification.class).build(); - job.getJobDataMap().put("task", taskName); + JobDetail job = JobBuilder.newJob(NtfyTaskStartNotification.class) + .withIdentity(String.valueOf(advancedTaskSchedule.getScheduleID())) + .build(); + job.getJobDataMap().put("task", advancedTaskSchedule.getTask().getTaskName()); job.getJobDataMap().put("ntfy_host", ntfy_host); job.getJobDataMap().put("ntfy_topic", ntfy_topic); job.getJobDataMap().put("frontend_domain", frontend_domain); - Trigger immediatly = TriggerBuilder.newTrigger().startNow().build(); + Trigger trigger = TriggerBuilder.newTrigger().startAt(calculateDelayInMillis(advancedTaskSchedule.getScheduleStart())).build(); - scheduler.scheduleJob(job, immediatly); + scheduler.scheduleJob(job, trigger); } public static void scheduleTask() throws SchedulerException { @@ -64,4 +77,16 @@ public class TaskSchedulingService { private static Date calculateDelayInMillis(LocalDateTime executionTime) { return Date.from(executionTime.atZone(ZoneId.systemDefault()).toInstant()); } + + @Scheduled(cron = "0 0 0 * * *") + public void scheduleStartReminders() throws SchedulerException { + List advancedTaskSchedules = taskScheduleService.findSchedulesByDate(LocalDate.now()); + for(AdvancedTaskSchedule advancedTaskSchedule : advancedTaskSchedules) { + scheduleStartingTask(advancedTaskSchedule); + } + } + + public void stopStartReminderNotification(AdvancedTaskSchedule schedule) throws SchedulerException { + scheduler.deleteJob(JobKey.jobKey(String.valueOf(schedule.getScheduleID()))); + } } From 4653ab9866f6956f4de81fa19cda9e9d0953000d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 14:43:45 +0100 Subject: [PATCH 07/10] Use user dependent ntfy data --- .../core/api/controller/NtfyController.java | 55 +++++++++++++++++++ .../api/models/users/NtfyInformation.java | 53 ++++++++++++++++++ backend/src/main/java/core/entities/User.java | 37 +++++++++++++ .../main/java/core/services/UserService.java | 10 ++++ .../services/ntfy/TaskSchedulingService.java | 36 ++---------- 5 files changed, 160 insertions(+), 31 deletions(-) create mode 100644 backend/src/main/java/core/api/controller/NtfyController.java create mode 100644 backend/src/main/java/core/api/models/users/NtfyInformation.java diff --git a/backend/src/main/java/core/api/controller/NtfyController.java b/backend/src/main/java/core/api/controller/NtfyController.java new file mode 100644 index 0000000..dd14b76 --- /dev/null +++ b/backend/src/main/java/core/api/controller/NtfyController.java @@ -0,0 +1,55 @@ +package core.api.controller; + +import core.api.models.auth.SimpleStatusResponse; +import core.api.models.users.NtfyInformation; +import core.entities.User; +import core.repositories.UserRepository; +import core.services.UserService; +import core.services.ntfy.TaskSchedulingService; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.Optional; + +@CrossOrigin(origins = "*", maxAge = 3600) +@RestController +@RequestMapping("/api") +public class NtfyController { + + @Autowired private UserRepository userRepository; + @Autowired private UserService userService; + @Autowired private TaskSchedulingService taskSchedulingService; + @GetMapping("/ntfy") + public ResponseEntity getNtfyInformation() { + String username = SecurityContextHolder.getContext().getAuthentication().getName(); + + Optional userOptional = userRepository.findByUsername(username); + if(userOptional.isPresent()) { + return ResponseEntity.ok(new NtfyInformation(userOptional.get())); + } else { + return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); + } + } + + @PostMapping("/ntfy") + public ResponseEntity editNtfyInformation(@Valid @RequestBody NtfyInformation ntfyInformation) { + String username = SecurityContextHolder.getContext().getAuthentication().getName(); + Optional user = userRepository.findByUsername(username); + if(user.isPresent()) { + userService.editNtfyInformation(user.get(), ntfyInformation); + try { + taskSchedulingService.scheduleStartReminders(); + } catch (SchedulerException e) { + throw new RuntimeException(e); + } + return ResponseEntity.ok(new SimpleStatusResponse("success")); + } else { + return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); + } + } +} diff --git a/backend/src/main/java/core/api/models/users/NtfyInformation.java b/backend/src/main/java/core/api/models/users/NtfyInformation.java new file mode 100644 index 0000000..4aa8726 --- /dev/null +++ b/backend/src/main/java/core/api/models/users/NtfyInformation.java @@ -0,0 +1,53 @@ +package core.api.models.users; + +import core.entities.User; + +public class NtfyInformation { + + private String ntfy_host; + private String ntfy_topic; + private String ntfy_user; + private String ntfy_token; + + public NtfyInformation(User user) { + this.ntfy_host = user.getNtfy_host(); + this.ntfy_topic = user.getNtfy_topic(); + this.ntfy_user = "****"; + this.ntfy_token = "****"; + } + + public NtfyInformation() { + } + + public String getNtfy_host() { + return ntfy_host; + } + + public void setNtfy_host(String ntfy_host) { + this.ntfy_host = ntfy_host; + } + + public String getNtfy_topic() { + return ntfy_topic; + } + + public void setNtfy_topic(String ntfy_topic) { + this.ntfy_topic = ntfy_topic; + } + + public String getNtfy_user() { + return ntfy_user; + } + + public void setNtfy_user(String ntfy_user) { + this.ntfy_user = ntfy_user; + } + + public String getNtfy_token() { + return ntfy_token; + } + + public void setNtfy_token(String ntfy_token) { + this.ntfy_token = ntfy_token; + } +} diff --git a/backend/src/main/java/core/entities/User.java b/backend/src/main/java/core/entities/User.java index 3b0849c..68271d4 100644 --- a/backend/src/main/java/core/entities/User.java +++ b/backend/src/main/java/core/entities/User.java @@ -42,6 +42,11 @@ public class User { inverseJoinColumns = @JoinColumn(name = "role_id")) private Set roles = new HashSet<>(); + private String ntfy_host; + private String ntfy_topic; + private String ntfy_username; + private String ntfy_token; + public User() { } @@ -98,6 +103,38 @@ public class User { this.roles = roles; } + public String getNtfy_host() { + return ntfy_host; + } + + public void setNtfy_host(String ntfy_host) { + this.ntfy_host = ntfy_host; + } + + public String getNtfy_topic() { + return ntfy_topic; + } + + public void setNtfy_topic(String ntfy_topic) { + this.ntfy_topic = ntfy_topic; + } + + public String getNtfy_username() { + return ntfy_username; + } + + public void setNtfy_username(String ntfy_username) { + this.ntfy_username = ntfy_username; + } + + public String getNtfy_token() { + return ntfy_token; + } + + public void setNtfy_token(String ntfy_token) { + this.ntfy_token = ntfy_token; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/backend/src/main/java/core/services/UserService.java b/backend/src/main/java/core/services/UserService.java index e149fbe..5d6ca7b 100644 --- a/backend/src/main/java/core/services/UserService.java +++ b/backend/src/main/java/core/services/UserService.java @@ -3,6 +3,7 @@ package core.services; import core.api.models.account.AccountDeleteRequest; import core.api.models.account.EmailChangeRequest; import core.api.models.account.PasswordChangeRequest; +import core.api.models.users.NtfyInformation; import core.api.models.users.UserAddInfo; import core.api.models.users.UserInfo; import core.api.models.users.UserUpdateInfo; @@ -152,4 +153,13 @@ public class UserService { userRepository.deleteByUsername(username); return 0; } + + public void editNtfyInformation(User user, NtfyInformation ntfyInformation) { + user.setNtfy_host(ntfyInformation.getNtfy_host()); + user.setNtfy_topic(ntfyInformation.getNtfy_topic()); + user.setNtfy_username(ntfyInformation.getNtfy_user()); + user.setNtfy_token(ntfyInformation.getNtfy_token()); + + userRepository.save(user); + } } diff --git a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java index ca34cb9..e8fe225 100644 --- a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java +++ b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java @@ -22,12 +22,6 @@ import java.util.List; @Service public class TaskSchedulingService { - @Value("${ntfy.host}") - private String ntfy_host; - - @Value("${ntfy.topic}") - private String ntfy_topic; - @Value("${frontend.domain}") private String frontend_domain; @@ -43,8 +37,8 @@ public class TaskSchedulingService { .withIdentity(String.valueOf(advancedTaskSchedule.getScheduleID())) .build(); job.getJobDataMap().put("task", advancedTaskSchedule.getTask().getTaskName()); - job.getJobDataMap().put("ntfy_host", ntfy_host); - job.getJobDataMap().put("ntfy_topic", ntfy_topic); + job.getJobDataMap().put("ntfy_host", advancedTaskSchedule.getTask().getTaskgroup().getUser().getNtfy_host()); + job.getJobDataMap().put("ntfy_topic", advancedTaskSchedule.getTask().getTaskgroup().getUser().getNtfy_topic()); job.getJobDataMap().put("frontend_domain", frontend_domain); Trigger trigger = TriggerBuilder.newTrigger().startAt(calculateDelayInMillis(advancedTaskSchedule.getScheduleStart())).build(); @@ -52,28 +46,6 @@ public class TaskSchedulingService { scheduler.scheduleJob(job, trigger); } - public static void scheduleTask() throws SchedulerException { - Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); - scheduler.start(); - - JobDetail job = JobBuilder.newJob(NtfyTask.class).build(); - - job.getJobDataMap().put("data", "A simple Job 1 Message"); - - LocalDateTime executionTime = LocalDateTime.of(2024, 3, 14, 9, 18); // Example: March 15, 2024, 10:00 AM - - Trigger trigger = TriggerBuilder.newTrigger() - .withIdentity("trigger1", "Group 1") - .startAt(calculateDelayInMillis(executionTime)).build(); - Trigger trigger2 = TriggerBuilder.newTrigger() - .withIdentity("trigger2", "Group 1") - .startAt(calculateDelayInMillis(executionTime.plusMinutes(1))).build(); - - Trigger immediatly = TriggerBuilder.newTrigger().withIdentity("Immediately", "Group 1").startNow().build(); - - scheduler.scheduleJob(job, immediatly); - } - private static Date calculateDelayInMillis(LocalDateTime executionTime) { return Date.from(executionTime.atZone(ZoneId.systemDefault()).toInstant()); } @@ -82,7 +54,9 @@ public class TaskSchedulingService { public void scheduleStartReminders() throws SchedulerException { List advancedTaskSchedules = taskScheduleService.findSchedulesByDate(LocalDate.now()); for(AdvancedTaskSchedule advancedTaskSchedule : advancedTaskSchedules) { - scheduleStartingTask(advancedTaskSchedule); + if(advancedTaskSchedule.getTask().getTaskgroup().getUser().getNtfy_host() != null) { + scheduleStartingTask(advancedTaskSchedule); + } } } From 4155af45f50c92b96595a1ea6a11cd97f9217f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 14:44:06 +0100 Subject: [PATCH 08/10] Frontend to update ntfy data --- frontend/src/api/.openapi-generator/FILES | 2 + frontend/src/api/api.module.ts | 1 + frontend/src/api/api/api.ts | 4 +- frontend/src/api/api/ntfy.service.ts | 210 ++++++++++++++++++ frontend/src/api/model/models.ts | 1 + frontend/src/api/model/ntfyInformation.ts | 32 +++ frontend/src/app/app.module.ts | 4 + .../connection-settings.component.css | 0 .../connection-settings.component.html | 1 + .../connection-settings.component.spec.ts | 21 ++ .../connection-settings.component.ts | 10 + .../ntfy-settings/ntfy-settings.component.css | 0 .../ntfy-settings.component.html | 24 ++ .../ntfy-settings.component.spec.ts | 21 ++ .../ntfy-settings/ntfy-settings.component.ts | 49 ++++ .../user-settings.component.html | 6 + openapi.yaml | 71 +++++- 17 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 frontend/src/api/api/ntfy.service.ts create mode 100644 frontend/src/api/model/ntfyInformation.ts create mode 100644 frontend/src/app/user-settings/connection-settings/connection-settings.component.css create mode 100644 frontend/src/app/user-settings/connection-settings/connection-settings.component.html create mode 100644 frontend/src/app/user-settings/connection-settings/connection-settings.component.spec.ts create mode 100644 frontend/src/app/user-settings/connection-settings/connection-settings.component.ts create mode 100644 frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.css create mode 100644 frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.html create mode 100644 frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.spec.ts create mode 100644 frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.ts diff --git a/frontend/src/api/.openapi-generator/FILES b/frontend/src/api/.openapi-generator/FILES index fa0da49..3595c4b 100644 --- a/frontend/src/api/.openapi-generator/FILES +++ b/frontend/src/api/.openapi-generator/FILES @@ -5,6 +5,7 @@ api/account.service.ts api/api.ts api/history.service.ts api/login.service.ts +api/ntfy.service.ts api/properties.service.ts api/schedule.service.ts api/task.service.ts @@ -32,6 +33,7 @@ model/loginRequest.ts model/loginResponse.ts model/manualScheduleStopInfo.ts model/models.ts +model/ntfyInformation.ts model/passwordChangeRequest.ts model/propertiesInfo.ts model/propertyInfo.ts diff --git a/frontend/src/api/api.module.ts b/frontend/src/api/api.module.ts index 1a6b886..63562e7 100644 --- a/frontend/src/api/api.module.ts +++ b/frontend/src/api/api.module.ts @@ -5,6 +5,7 @@ import { HttpClient } from '@angular/common/http'; import { AccountService } from './api/account.service'; import { HistoryService } from './api/history.service'; import { LoginService } from './api/login.service'; +import { NtfyService } from './api/ntfy.service'; import { PropertiesService } from './api/properties.service'; import { ScheduleService } from './api/schedule.service'; import { TaskService } from './api/task.service'; diff --git a/frontend/src/api/api/api.ts b/frontend/src/api/api/api.ts index d483dcf..75dbaae 100644 --- a/frontend/src/api/api/api.ts +++ b/frontend/src/api/api/api.ts @@ -4,6 +4,8 @@ export * from './history.service'; import { HistoryService } from './history.service'; export * from './login.service'; import { LoginService } from './login.service'; +export * from './ntfy.service'; +import { NtfyService } from './ntfy.service'; export * from './properties.service'; import { PropertiesService } from './properties.service'; export * from './schedule.service'; @@ -14,4 +16,4 @@ export * from './taskgroup.service'; import { TaskgroupService } from './taskgroup.service'; export * from './users.service'; import { UsersService } from './users.service'; -export const APIS = [AccountService, HistoryService, LoginService, PropertiesService, ScheduleService, TaskService, TaskgroupService, UsersService]; +export const APIS = [AccountService, HistoryService, LoginService, NtfyService, PropertiesService, ScheduleService, TaskService, TaskgroupService, UsersService]; diff --git a/frontend/src/api/api/ntfy.service.ts b/frontend/src/api/api/ntfy.service.ts new file mode 100644 index 0000000..facc48a --- /dev/null +++ b/frontend/src/api/api/ntfy.service.ts @@ -0,0 +1,210 @@ +/** + * API Title + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +/* tslint:disable:no-unused-variable member-ordering */ + +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent, HttpParameterCodec, HttpContext + } from '@angular/common/http'; +import { CustomHttpParameterCodec } from '../encoder'; +import { Observable } from 'rxjs'; + +import { NtfyInformation } from '../model/models'; +import { SimpleStatusResponse } from '../model/models'; + +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + + + +@Injectable({ + providedIn: 'root' +}) +export class NtfyService { + + protected basePath = 'http://127.0.0.1:8080/api'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + public encoder: HttpParameterCodec; + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (configuration) { + this.configuration = configuration; + } + if (typeof this.configuration.basePath !== 'string') { + if (typeof basePath !== 'string') { + basePath = this.basePath; + } + this.configuration.basePath = basePath; + } + this.encoder = this.configuration.encoder || new CustomHttpParameterCodec(); + } + + + private addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams { + if (typeof value === "object" && value instanceof Date === false) { + httpParams = this.addToHttpParamsRecursive(httpParams, value); + } else { + httpParams = this.addToHttpParamsRecursive(httpParams, value, key); + } + return httpParams; + } + + private addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams { + if (value == null) { + return httpParams; + } + + if (typeof value === "object") { + if (Array.isArray(value)) { + (value as any[]).forEach( elem => httpParams = this.addToHttpParamsRecursive(httpParams, elem, key)); + } else if (value instanceof Date) { + if (key != null) { + httpParams = httpParams.append(key, + (value as Date).toISOString().substr(0, 10)); + } else { + throw Error("key may not be null if value is Date"); + } + } else { + Object.keys(value).forEach( k => httpParams = this.addToHttpParamsRecursive( + httpParams, value[k], key != null ? `${key}.${k}` : k)); + } + } else if (key != null) { + httpParams = httpParams.append(key, value); + } else { + throw Error("key may not be null if value is not object or array"); + } + return httpParams; + } + + /** + * Get ntfy information + * Get ntfy information + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public ntfyGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public ntfyGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public ntfyGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public ntfyGet(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + + let localVarHeaders = this.defaultHeaders; + + let localVarCredential: string | undefined; + // authentication (API_TOKEN) required + localVarCredential = this.configuration.lookupCredential('API_TOKEN'); + if (localVarCredential) { + localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential); + } + + let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; + if (localVarHttpHeaderAcceptSelected === undefined) { + // to determine the Accept header + const httpHeaderAccepts: string[] = [ + 'application/json' + ]; + localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); + } + if (localVarHttpHeaderAcceptSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); + } + + let localVarHttpContext: HttpContext | undefined = options && options.context; + if (localVarHttpContext === undefined) { + localVarHttpContext = new HttpContext(); + } + + + let responseType_: 'text' | 'json' = 'json'; + if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) { + responseType_ = 'text'; + } + + return this.httpClient.get(`${this.configuration.basePath}/ntfy`, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * Edit ntfy information + * Edit ntfy information + * @param ntfyInformation + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public ntfyPost(ntfyInformation?: NtfyInformation, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public ntfyPost(ntfyInformation?: NtfyInformation, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public ntfyPost(ntfyInformation?: NtfyInformation, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public ntfyPost(ntfyInformation?: NtfyInformation, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + + let localVarHeaders = this.defaultHeaders; + + let localVarCredential: string | undefined; + // authentication (API_TOKEN) required + localVarCredential = this.configuration.lookupCredential('API_TOKEN'); + if (localVarCredential) { + localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential); + } + + let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; + if (localVarHttpHeaderAcceptSelected === undefined) { + // to determine the Accept header + const httpHeaderAccepts: string[] = [ + 'application/json' + ]; + localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); + } + if (localVarHttpHeaderAcceptSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); + } + + let localVarHttpContext: HttpContext | undefined = options && options.context; + if (localVarHttpContext === undefined) { + localVarHttpContext = new HttpContext(); + } + + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected); + } + + let responseType_: 'text' | 'json' = 'json'; + if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) { + responseType_ = 'text'; + } + + return this.httpClient.post(`${this.configuration.basePath}/ntfy`, + ntfyInformation, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + +} diff --git a/frontend/src/api/model/models.ts b/frontend/src/api/model/models.ts index 466da64..028c0ee 100644 --- a/frontend/src/api/model/models.ts +++ b/frontend/src/api/model/models.ts @@ -15,6 +15,7 @@ export * from './inlineResponse409'; export * from './loginRequest'; export * from './loginResponse'; export * from './manualScheduleStopInfo'; +export * from './ntfyInformation'; export * from './passwordChangeRequest'; export * from './propertiesInfo'; export * from './propertyInfo'; diff --git a/frontend/src/api/model/ntfyInformation.ts b/frontend/src/api/model/ntfyInformation.ts new file mode 100644 index 0000000..5919525 --- /dev/null +++ b/frontend/src/api/model/ntfyInformation.ts @@ -0,0 +1,32 @@ +/** + * API Title + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export interface NtfyInformation { + /** + * host of ntfy service + */ + ntfy_host: string; + /** + * topic of ntfy service + */ + ntfy_topic: string; + /** + * username of ntfy account for publishing news + */ + ntfy_user: string; + /** + * token to ntfy useraccount + */ + ntfy_token?: string; +} + diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 99fa84e..61f2d42 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -89,6 +89,8 @@ import { ScheduleHistoryComponent } from './statistics/schedule-history/schedule import {MatButtonToggleModule} from "@angular/material/button-toggle"; import {MatGridListModule} from "@angular/material/grid-list"; import { StopScheduleManuallyComponent } from './dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component'; +import { ConnectionSettingsComponent } from './user-settings/connection-settings/connection-settings.component'; +import { NtfySettingsComponent } from './user-settings/connection-settings/ntfy-settings/ntfy-settings.component'; @NgModule({ declarations: [ AppComponent, @@ -134,6 +136,8 @@ import { StopScheduleManuallyComponent } from './dashboard/active-schedule/stop- HeatmapActivityComponent, ScheduleHistoryComponent, StopScheduleManuallyComponent, + ConnectionSettingsComponent, + NtfySettingsComponent, ], imports: [ BrowserModule, diff --git a/frontend/src/app/user-settings/connection-settings/connection-settings.component.css b/frontend/src/app/user-settings/connection-settings/connection-settings.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/user-settings/connection-settings/connection-settings.component.html b/frontend/src/app/user-settings/connection-settings/connection-settings.component.html new file mode 100644 index 0000000..376ad7e --- /dev/null +++ b/frontend/src/app/user-settings/connection-settings/connection-settings.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/user-settings/connection-settings/connection-settings.component.spec.ts b/frontend/src/app/user-settings/connection-settings/connection-settings.component.spec.ts new file mode 100644 index 0000000..28ff0a8 --- /dev/null +++ b/frontend/src/app/user-settings/connection-settings/connection-settings.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConnectionSettingsComponent } from './connection-settings.component'; + +describe('ConnectionSettingsComponent', () => { + let component: ConnectionSettingsComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ConnectionSettingsComponent] + }); + fixture = TestBed.createComponent(ConnectionSettingsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/user-settings/connection-settings/connection-settings.component.ts b/frontend/src/app/user-settings/connection-settings/connection-settings.component.ts new file mode 100644 index 0000000..aa9b358 --- /dev/null +++ b/frontend/src/app/user-settings/connection-settings/connection-settings.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-connection-settings', + templateUrl: './connection-settings.component.html', + styleUrls: ['./connection-settings.component.css'] +}) +export class ConnectionSettingsComponent { + +} diff --git a/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.css b/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.html b/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.html new file mode 100644 index 0000000..560cfc7 --- /dev/null +++ b/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.html @@ -0,0 +1,24 @@ + + Hostname + + + + + Topic + + + + + Username + + + + + Token + + + +
+ +
+ diff --git a/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.spec.ts b/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.spec.ts new file mode 100644 index 0000000..1620a14 --- /dev/null +++ b/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NtfySettingsComponent } from './ntfy-settings.component'; + +describe('NtfySettingsComponent', () => { + let component: NtfySettingsComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [NtfySettingsComponent] + }); + fixture = TestBed.createComponent(NtfySettingsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.ts b/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.ts new file mode 100644 index 0000000..3b9e8ee --- /dev/null +++ b/frontend/src/app/user-settings/connection-settings/ntfy-settings/ntfy-settings.component.ts @@ -0,0 +1,49 @@ +import { Component } from '@angular/core'; +import {NtfyService} from "../../../../api"; +import {Form, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms"; +import {MatSnackBar} from "@angular/material/snack-bar"; + +@Component({ + selector: 'app-ntfy-settings', + templateUrl: './ntfy-settings.component.html', + styleUrls: ['./ntfy-settings.component.css'] +}) +export class NtfySettingsComponent { + + host_formCtrl = new FormControl('', [Validators.required]) + topic_formCtrl = new FormControl('', [Validators.required]) + user_formCtrl = new FormControl('', [Validators.required]) + token_formCtrl = new FormControl('', [Validators.required]) + + constructor(private ntfyService: NtfyService, + private snackbar: MatSnackBar) { + } + + ngOnInit() { + this.ntfyService.ntfyGet().subscribe({ + next: resp => { + this.host_formCtrl.setValue(resp.ntfy_host); + this.topic_formCtrl.setValue(resp.ntfy_topic); + this.user_formCtrl.setValue(resp.ntfy_user); + this.token_formCtrl.setValue(resp.ntfy_token!); + } + }) + } + + save() { + const token = this.token_formCtrl.value === "****" ? "" : this.token_formCtrl.value! + const user = this.user_formCtrl.value === "****" ? "" : this.user_formCtrl.value! + this.ntfyService.ntfyPost({ + ntfy_host: this.host_formCtrl.value!, + ntfy_topic: this.topic_formCtrl.value!, + ntfy_token: token, + ntfy_user: user + }).subscribe({ + next: resp => { + this.snackbar.open("Ntfy-Configuration updated", "", {duration: 2000}) + this.user_formCtrl.setValue("****"); + this.token_formCtrl.setValue("****"); + } + }) + } +} diff --git a/frontend/src/app/user-settings/user-settings.component.html b/frontend/src/app/user-settings/user-settings.component.html index f11bfb6..044e1b5 100644 --- a/frontend/src/app/user-settings/user-settings.component.html +++ b/frontend/src/app/user-settings/user-settings.component.html @@ -4,4 +4,10 @@ + + +
+ +
+
diff --git a/openapi.yaml b/openapi.yaml index 997da1b..2001027 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2027,7 +2027,53 @@ paths: type: array items: $ref: '#/components/schemas/ScheduleInfo' - + /ntfy: + get: + security: + - API_TOKEN: [] + tags: + - ntfy + description: Get ntfy information + summary: Get ntfy information + responses: + 200: + description: Operation successfull + content: + application/json: + schema: + $ref: '#/components/schemas/NtfyInformation' + 404: + description: Not found + content: + application/json: + schema: + $ref: '#/components/schemas/SimpleStatusResponse' + post: + security: + - API_TOKEN: [] + tags: + - ntfy + description: Edit ntfy information + summary: Edit ntfy information + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/NtfyInformation' + responses: + 200: + description: Operation successfull + content: + application/json: + schema: + $ref: '#/components/schemas/SimpleStatusResponse' + 404: + description: Operation successfull + content: + application/json: + schema: + $ref: '#/components/schemas/SimpleStatusResponse' + components: securitySchemes: @@ -2712,4 +2758,25 @@ components: duration: type: number description: duration in minutes - example: 10 \ No newline at end of file + example: 10 + NtfyInformation: + required: + - ntfy_host + - ntfy_topic + additionalProperties: false + properties: + ntfy_host: + type: string + description: host of ntfy service + example: https://ntfy.fawkes100.de + ntfy_topic: + type: string + description: topic of ntfy service + example: Topicname + ntfy_user: + type: string + description: username of ntfy account for publishing news + example: password + ntfy_token: + type: string + description: token to ntfy useraccount \ No newline at end of file From 526c57a36273fdbacb1554d2d8437afaf5300fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 14:46:59 +0100 Subject: [PATCH 09/10] Do not ntfy on already performed scheduled or missed schedules --- backend/src/main/java/core/services/TaskScheduleService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index 3ee3e70..57ed6d2 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -231,7 +231,8 @@ public class TaskScheduleService { Iterable allSchedules = advancedScheduleRepository.findAll(); List schedulesToday = new ArrayList<>(); for(AdvancedTaskSchedule advancedTaskSchedule : allSchedules) { - if(advancedTaskSchedule.getScheduleStart().toLocalDate().equals(date)) { + if(advancedTaskSchedule.getScheduleStart().toLocalDate().equals(date) && advancedTaskSchedule.getStartTime() == null && + advancedTaskSchedule.getScheduleStart().isBefore(LocalDateTime.now())) { schedulesToday.add(advancedTaskSchedule); } } From 19075b2b1dfc899f6bf85490793d3be427aba718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Thu, 14 Mar 2024 14:56:02 +0100 Subject: [PATCH 10/10] Send ntf-msg when schedule is started --- .../api/controller/ScheduleController.java | 4 +++- .../services/ntfy/TaskSchedulingService.java | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java index dcf1c52..5242b9d 100644 --- a/backend/src/main/java/core/api/controller/ScheduleController.java +++ b/backend/src/main/java/core/api/controller/ScheduleController.java @@ -175,6 +175,7 @@ public class ScheduleController { if(scheduleResult.getExitCode() == ServiceExitCode.ENTITY_ALREADY_EXIST) { return ResponseEntity.status(409).body(new SimpleStatusResponse("failed")); } else { + taskSchedulingService.sendRunningTaskNotification(scheduleResult.getResult()); return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo()); } } @@ -204,11 +205,12 @@ public class ScheduleController { if(serviceResult.getResult() instanceof AdvancedTaskSchedule) { try { taskSchedulingService.stopStartReminderNotification((AdvancedTaskSchedule) serviceResult.getResult()); + } catch (SchedulerException e) { throw new RuntimeException(e); } } - + taskSchedulingService.sendRunningTaskNotification(serviceResult.getResult()); return ResponseEntity.ok(new ScheduleActivateResponse(serviceResult.getResult().getStartTime())); } diff --git a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java index e8fe225..62702b5 100644 --- a/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java +++ b/backend/src/main/java/core/services/ntfy/TaskSchedulingService.java @@ -1,6 +1,7 @@ package core.services.ntfy; +import core.entities.User; import core.entities.timemanager.AbstractSchedule; import core.entities.timemanager.AdvancedTaskSchedule; import core.repositories.timemanager.ScheduleRepository; @@ -13,6 +14,11 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; @@ -46,6 +52,24 @@ public class TaskSchedulingService { scheduler.scheduleJob(job, trigger); } + public void sendRunningTaskNotification(AbstractSchedule abstractSchedule) { + HttpClient httpClient = HttpClient.newHttpClient(); + User user = abstractSchedule.getTask().getTaskgroup().getUser(); + try { + HttpRequest request = HttpRequest.newBuilder() + .uri(new URI(user.getNtfy_host()+ "/" + user.getNtfy_topic())) + .POST(HttpRequest.BodyPublishers.ofString("Running Task " + abstractSchedule.getTask().getTaskName())) + .header("Tags", "heavy_check_mark") + .header("Title", "Task Running") + .header("Actions", "view, Open TimeScheduler, "+frontend_domain+", clear=true") + .build(); + + httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + private static Date calculateDelayInMillis(LocalDateTime executionTime) { return Date.from(executionTime.atZone(ZoneId.systemDefault()).toInstant()); }