From 27f7a2ad42f943c7d2aa149fa2befb7cac479823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 11 Nov 2023 13:24:17 +0100 Subject: [PATCH 01/18] Update gitignore and add Clear ScheduleCode --- .gitignore | 57 ++--- .../api/controller/ScheduleController.java | 229 ------------------ .../core/api/controller/TaskController.java | 2 - .../AbstractScheduleShortInfo.java | 4 - .../taskSchedule/BasicScheduleShortInfo.java | 22 -- .../BasicTaskScheduleEntityInfo.java | 53 ---- .../BasicTaskScheduleFieldInfo.java | 17 -- .../taskSchedule/ForgottenActivity.java | 22 -- .../taskSchedule/ForgottenActivityMode.java | 8 - .../taskSchedule/ScheduleActivateInfo.java | 21 -- .../taskSchedule/ScheduleInfo.java | 114 --------- .../taskSchedule/ScheduleStatus.java | 28 --- .../TaskScheduleStopResponse.java | 18 -- .../BasicTaskScheduleRepository.java | 26 -- .../core/services/TaskScheduleService.java | 219 ----------------- 15 files changed, 29 insertions(+), 811 deletions(-) delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/AbstractScheduleShortInfo.java delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleShortInfo.java delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicTaskScheduleEntityInfo.java delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicTaskScheduleFieldInfo.java delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/ForgottenActivity.java delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/ForgottenActivityMode.java delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleActivateInfo.java delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleInfo.java delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleStatus.java delete mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/TaskScheduleStopResponse.java diff --git a/.gitignore b/.gitignore index 301464f..9a934a1 100644 --- a/.gitignore +++ b/.gitignore @@ -27,44 +27,45 @@ replay_pid* # ---> JetBrains # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 -.idea/ +**/.idea/ # User-specific stff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf +**/.idea/**/workspace.xml +**/.idea/**/tasks.xml +**/.idea/**/usage.statistics.xml +**/.idea/**/dictionaries +**/.idea/**/shelf # AWS User-specific -.idea/**/aws.xml +**/.idea/**/aws.xml # Generated files -.idea/**/contentModel.xml +**/.idea/**/contentModel.xml # Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml +**/.idea/**/dataSources/ +**/.idea/**/dataSources.ids +**/.idea/**/dataSources.local.xml +**/.idea/**/sqlDataSources.xml +**/.idea/**/dynamic.xml +**/.idea/**/uiDesigner.xml +**/.idea/**/dbnavigator.xml # Gradle -.idea/**/gradle.xml -.idea/**/libraries +**/.idea/**/gradle.xml +**/.idea/**/libraries + # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules +# **/.idea/artifacts +# **/.idea/compiler.xml +# **/.idea/jarRepositories.xml +# **/.idea/modules.xml +# **/.idea/*.iml +# **/.idea/modules # *.iml # *.ipr @@ -72,7 +73,7 @@ replay_pid* cmake-build-*/ # Mongo Explorer plugin -.idea/**/mongoSettings.xml +**/.idea/**/mongoSettings.xml # File-based project format *.iws @@ -87,10 +88,10 @@ out/ atlassian-ide-plugin.xml # Cursive Clojure plugin -.idea/replstate.xml +**/.idea/replstate.xml # SonarLint plugin -.idea/sonarlint/ +**/.idea/sonarlint/ # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml @@ -99,10 +100,10 @@ crashlytics-build.properties fabric.properties # Editor-based Rest Client -.idea/httpRequests +**/.idea/httpRequests # Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser +**/.idea/caches/build_file_checksums.ser # ---> Maven target/ diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java index f47b2c4..5406dfe 100644 --- a/backend/src/main/java/core/api/controller/ScheduleController.java +++ b/backend/src/main/java/core/api/controller/ScheduleController.java @@ -22,234 +22,5 @@ import java.util.*; @RequestMapping("/api") public class ScheduleController { - private final TaskService taskService; - private final TaskScheduleService taskScheduleService; - private final BasicTaskScheduleRepository basicTaskScheduleRepository; - private final UserRepository userRepository; - public ScheduleController(@Autowired TaskService taskService, @Autowired TaskScheduleService taskScheduleService, - BasicTaskScheduleRepository basicTaskScheduleRepository, - UserRepository userRepository) { - this.taskService = taskService; - this.taskScheduleService = taskScheduleService; - this.basicTaskScheduleRepository = basicTaskScheduleRepository; - this.userRepository = userRepository; - } - - @GetMapping("/schedules/{taskID}/{scheduleType}") - public ResponseEntity loadSchedulesOfTask(@PathVariable long taskID, @PathVariable ScheduleType scheduleType) { - PermissionResult taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); - if(!taskPermissionResult.isHasPermissions()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - if(taskPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - - switch (scheduleType) { - case BASIC -> { - List basicTaskScheduleList = new ArrayList<>(taskPermissionResult.getResult().getBasicTaskSchedules()); - basicTaskScheduleList.sort(Comparator.comparing(BasicTaskSchedule::getScheduleDate)); - return ResponseEntity.ok(basicTaskScheduleList.stream().map(BasicTaskScheduleEntityInfo::new)); - } - case ADVANCED, MODERATE -> ResponseEntity.ok(new ArrayList<>()); - } - return null; - } - - @PutMapping("/schedules/{taskID}/basic") - public ResponseEntity basicScheduleTask(@PathVariable long taskID, @Valid @RequestBody BasicTaskScheduleFieldInfo basicTaskSchedule) { - PermissionResult taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); - if(!taskPermissionResult.isHasPermissions()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - if(taskPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - - ServiceResult creationResult = taskScheduleService.createBasicTaskSchedule(taskPermissionResult.getResult(), basicTaskSchedule); - return ResponseEntity.ok(new BasicTaskScheduleEntityInfo(creationResult.getResult())); - } - - @PostMapping("/schedules/{scheduleID}/basic") - public ResponseEntity editScheduledTask(@PathVariable long scheduleID, @Valid @RequestBody BasicTaskScheduleFieldInfo basicTaskScheduleFieldInfo) { - PermissionResult permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); - if(!permissionResult.isHasPermissions()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - - taskScheduleService.reschedule(permissionResult.getResult(), basicTaskScheduleFieldInfo); - return ResponseEntity.ok(new SimpleStatusResponse("success")); - } - - @DeleteMapping("/schedules/{scheduleID}/{scheduleType}") - public ResponseEntity deleteScheduledTask(@PathVariable long scheduleID, @PathVariable ScheduleType scheduleType) { - PermissionResult permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); - if(!permissionResult.isHasPermissions()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - - taskScheduleService.deleteBasicSchedule(permissionResult.getResult()); - return ResponseEntity.ok(new SimpleStatusResponse("success")); - } - - @GetMapping("/schedules/today/{activateable}") - public ResponseEntity loadTodaysSchedules(@PathVariable boolean activateable) { - ServiceResult> todaysSchedules = taskScheduleService.loadTodaysSchedule(SecurityContextHolder.getContext().getAuthentication().getName(), activateable); - if(todaysSchedules.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } else { - return ResponseEntity.ok(todaysSchedules.getResult().stream().map(ScheduleInfo::new).toList()); - } - } - - @GetMapping("/schedules") - public ResponseEntity loadSchedules() { - ServiceResult> schedules = taskScheduleService.loadSchedules(SecurityContextHolder.getContext().getAuthentication().getName()); - if(schedules.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } else { - return ResponseEntity.ok(schedules.getResult().stream().map(ScheduleInfo::new).toList()); - } - } - @PostMapping("/schedules/{taskID}/now") - public ResponseEntity scheduleTaskNow(@PathVariable long taskID) { - PermissionResult permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); - if(!permissionResult.isHasPermissions()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - - ServiceResult scheduleResult = taskScheduleService.scheduleTaskNow(permissionResult.getResult()); - if(scheduleResult.getExitCode() == ServiceExitCode.ENTITY_ALREADY_EXIST) { - return ResponseEntity.status(409).body(new SimpleStatusResponse("failed")); - } else { - return ResponseEntity.ok(new ScheduleInfo(scheduleResult.getResult())); - } - } - - @GetMapping("/schedules/active") - public ResponseEntity getActiveSchedule() { - ServiceResult activeScheduleResult = taskScheduleService.getActiveSchedule(SecurityContextHolder.getContext().getAuthentication().getName()); - if(activeScheduleResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.ok(new ScheduleInfo()); - } else { - return ResponseEntity.ok(new ScheduleInfo(activeScheduleResult.getResult())); - } - } - - @PostMapping("/schedules/{scheduleID}/activate") - public ResponseEntity activateSchedule(@PathVariable long scheduleID) { - PermissionResult schedulePermissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); - if(!schedulePermissionResult.isHasPermissions()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - if(schedulePermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - - ServiceResult scheduleActivateResult = taskScheduleService.activateSchedule(schedulePermissionResult.getResult()); - if(scheduleActivateResult.getExitCode() == ServiceExitCode.ENTITY_ALREADY_EXIST) { - return ResponseEntity.status(409).body(new SimpleStatusResponse("failed")); - } else if(scheduleActivateResult.getExitCode() == ServiceExitCode.OK){ - return ResponseEntity.ok(new ScheduleActivateInfo(scheduleActivateResult.getResult().getStartTime())); - } else { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - } - - @PostMapping("/schedules/{scheduleID}/stop/{finish}") - public ResponseEntity stopSchedule(@PathVariable long scheduleID, @PathVariable boolean finish) { - PermissionResult schedulePermissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); - if(!schedulePermissionResult.isHasPermissions()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - if(schedulePermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - - ServiceResult stopResult = taskScheduleService.stopSchedule(schedulePermissionResult.getResult(), finish); - if(stopResult.getExitCode() == ServiceExitCode.INVALID_OPERATION) { - return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); - } else { - return ResponseEntity.ok(new TaskScheduleStopResponse(stopResult.getResult())); - } - } - - @GetMapping("/schedules/status/today") - public ResponseEntity getWorkedMinutesToday() { - Optional user = userRepository.findByUsername(SecurityContextHolder.getContext().getAuthentication().getName()); - if(user.isEmpty()) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - - int workedMinutes = taskScheduleService.getWorkedMinutes(user.get()); - return ResponseEntity.ok(new ScheduleStatus(workedMinutes, taskScheduleService.isAnyScheduleMissed(user.get()))); - } - - @PostMapping("/schedules/{taskID}/forgotten") - public ResponseEntity registerForgottenActivity(@PathVariable long taskID, @Valid @RequestBody ForgottenActivity forgottenActivity) { - PermissionResult permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); - if(!permissionResult.isHasPermissions()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - - ServiceResult serviceResult = taskScheduleService.registerForgottenActivity(permissionResult.getResult(), forgottenActivity); - if(serviceResult.getExitCode() == ServiceExitCode.INVALID_OPERATION) { - return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); - } else { - return ResponseEntity.ok(new TaskScheduleStopResponse(serviceResult.getResult())); - } - } - - @GetMapping("/schedules/missed") - public ResponseEntity loadMissedSchedules() { - Optional user = userRepository.findByUsername(SecurityContextHolder.getContext().getAuthentication().getName()); - if(user.isEmpty()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - List schedules = taskScheduleService.loadMissedSchedules(user.get()); - return ResponseEntity.ok(schedules.stream().map(ScheduleInfo::new).toList()); - } - - @DeleteMapping("/schedules/{scheduleIDs}/all") - public ResponseEntity deleteSchedules(@PathVariable long[] scheduleIDs) { - List schedulesToDelete = new LinkedList<>(); - for(long scheduleID: scheduleIDs) { - PermissionResult permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); - if(!permissionResult.isHasPermissions()) { - return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); - } - - if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { - return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); - } - schedulesToDelete.add(permissionResult.getResult()); - } - - for(BasicTaskSchedule schedule : schedulesToDelete) { - this.taskScheduleService.deleteBasicSchedule(schedule); - } - return ResponseEntity.ok(new SimpleStatusResponse("success")); - } } diff --git a/backend/src/main/java/core/api/controller/TaskController.java b/backend/src/main/java/core/api/controller/TaskController.java index 342640a..a6dff2c 100644 --- a/backend/src/main/java/core/api/controller/TaskController.java +++ b/backend/src/main/java/core/api/controller/TaskController.java @@ -1,7 +1,6 @@ package core.api.controller; import core.api.models.auth.SimpleStatusResponse; -import core.api.models.timemanager.taskSchedule.ScheduleInfo; import core.api.models.timemanager.tasks.*; import core.entities.timemanager.Task; import core.entities.timemanager.Taskgroup; @@ -13,7 +12,6 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; @CrossOrigin(origins = "*", maxAge = 3600) diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/AbstractScheduleShortInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/AbstractScheduleShortInfo.java deleted file mode 100644 index 1cc5365..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/AbstractScheduleShortInfo.java +++ /dev/null @@ -1,4 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -public abstract class AbstractScheduleShortInfo { -} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleShortInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleShortInfo.java deleted file mode 100644 index 2ba9de1..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleShortInfo.java +++ /dev/null @@ -1,22 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -import core.entities.timemanager.BasicTaskSchedule; - -import java.time.LocalDate; - -public class BasicScheduleShortInfo extends AbstractScheduleShortInfo { - - private LocalDate scheduleDate; - - public BasicScheduleShortInfo(BasicTaskSchedule basicTaskSchedule) { - this.scheduleDate = basicTaskSchedule.getScheduleDate(); - } - - public LocalDate getScheduleDate() { - return scheduleDate; - } - - public void setScheduleDate(LocalDate scheduleDate) { - this.scheduleDate = scheduleDate; - } -} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicTaskScheduleEntityInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicTaskScheduleEntityInfo.java deleted file mode 100644 index 992b8a4..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicTaskScheduleEntityInfo.java +++ /dev/null @@ -1,53 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -import core.entities.timemanager.BasicTaskSchedule; - -import java.time.LocalDate; -import java.time.LocalDateTime; - -public class BasicTaskScheduleEntityInfo { - - private long scheduleID; - private LocalDate scheduleDate; - private LocalDateTime startTime; - private LocalDateTime finishedTime; - - public BasicTaskScheduleEntityInfo(BasicTaskSchedule basicTaskSchedule) { - this.scheduleID = basicTaskSchedule.getScheduleID(); - this.scheduleDate = basicTaskSchedule.getScheduleDate(); - this.startTime = basicTaskSchedule.getStartTime(); - this.finishedTime = basicTaskSchedule.getFinishedTime(); - } - - public long getScheduleID() { - return scheduleID; - } - - public void setScheduleID(long scheduleID) { - this.scheduleID = scheduleID; - } - - public LocalDate getScheduleDate() { - return scheduleDate; - } - - public void setScheduleDate(LocalDate scheduleDate) { - this.scheduleDate = scheduleDate; - } - - public LocalDateTime getStartTime() { - return startTime; - } - - public void setStartTime(LocalDateTime startTime) { - this.startTime = startTime; - } - - public LocalDateTime getFinishedTime() { - return finishedTime; - } - - public void setFinishedTime(LocalDateTime finishedTime) { - this.finishedTime = finishedTime; - } -} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicTaskScheduleFieldInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicTaskScheduleFieldInfo.java deleted file mode 100644 index d8b53d5..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicTaskScheduleFieldInfo.java +++ /dev/null @@ -1,17 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -import javax.validation.constraints.NotNull; -import java.time.LocalDate; - -public class BasicTaskScheduleFieldInfo { - @NotNull - private LocalDate scheduleDate; - - public LocalDate getScheduleDate() { - return scheduleDate; - } - - public void setScheduleDate(LocalDate scheduleDate) { - this.scheduleDate = scheduleDate; - } -} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ForgottenActivity.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ForgottenActivity.java deleted file mode 100644 index d8634d1..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ForgottenActivity.java +++ /dev/null @@ -1,22 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -public class ForgottenActivity { - private ForgottenActivityMode mode; - private int minutesSpent; - - public ForgottenActivityMode getMode() { - return mode; - } - - public void setMode(ForgottenActivityMode mode) { - this.mode = mode; - } - - public int getMinutesSpent() { - return minutesSpent; - } - - public void setMinutesSpent(int minutesSpent) { - this.minutesSpent = minutesSpent; - } -} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ForgottenActivityMode.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ForgottenActivityMode.java deleted file mode 100644 index 70cd031..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ForgottenActivityMode.java +++ /dev/null @@ -1,8 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -public enum ForgottenActivityMode { - - MANUAL, - LAST, - PLANNED -} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleActivateInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleActivateInfo.java deleted file mode 100644 index 74a07fb..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleActivateInfo.java +++ /dev/null @@ -1,21 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -import java.time.LocalDate; -import java.time.LocalDateTime; - -public class ScheduleActivateInfo { - - private LocalDateTime startTime; - - public ScheduleActivateInfo(LocalDateTime startTime) { - this.startTime = startTime; - } - - public LocalDateTime getStartTime() { - return startTime; - } - - public void setStartTime(LocalDateTime startTime) { - this.startTime = startTime; - } -} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleInfo.java deleted file mode 100644 index 65a12c8..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleInfo.java +++ /dev/null @@ -1,114 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; -import core.api.models.timemanager.tasks.TaskShortInfo; -import core.entities.timemanager.BasicTaskSchedule; -import core.entities.timemanager.ScheduleType; -import core.entities.timemanager.Taskgroup; - -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.List; - -public class ScheduleInfo { - - private long scheduleID; - private ScheduleType scheduleType; - private LocalDateTime startTime; - - private LocalDateTime finishTime; - private int activeMinutes; - private AbstractScheduleShortInfo schedule; - - private List taskgroupPath; - - private TaskShortInfo task; - - public ScheduleInfo(BasicTaskSchedule basicTaskSchedule) { - this.scheduleID = basicTaskSchedule.getScheduleID(); - this.scheduleType = ScheduleType.BASIC; - this.startTime = basicTaskSchedule.getStartTime(); - this.finishTime = basicTaskSchedule.getFinishedTime(); - - if(this.finishTime == null && this.startTime != null) { - this.activeMinutes = (int) Duration.between(basicTaskSchedule.getStartTime(), LocalDateTime.now()).toMinutes(); - } else if(this.startTime != null){ - this.activeMinutes = (int) Duration.between(basicTaskSchedule.getStartTime(), basicTaskSchedule.getFinishedTime()).toMinutes(); - } - - this.schedule = new BasicScheduleShortInfo(basicTaskSchedule); - this.task = new TaskShortInfo(basicTaskSchedule.getTask()); - List taskgroupPath = Taskgroup.getAncestorList(basicTaskSchedule.getTask().getTaskgroup()); - taskgroupPath.add(basicTaskSchedule.getTask().getTaskgroup()); - this.taskgroupPath = taskgroupPath.stream().map(TaskgroupEntityInfo::new).toList(); - } - - public ScheduleInfo() { - this.scheduleID = -1; - } - - public long getScheduleID() { - return scheduleID; - } - - public void setScheduleID(long scheduleID) { - this.scheduleID = scheduleID; - } - - public ScheduleType getScheduleType() { - return scheduleType; - } - - public void setScheduleType(ScheduleType scheduleType) { - this.scheduleType = scheduleType; - } - - public LocalDateTime getStartTime() { - return startTime; - } - - public void setStartTime(LocalDateTime startTime) { - this.startTime = startTime; - } - - public LocalDateTime getFinishTime() { - return finishTime; - } - - public void setFinishTime(LocalDateTime finishTime) { - this.finishTime = finishTime; - } - - public int getActiveMinutes() { - return activeMinutes; - } - - public void setActiveMinutes(int activeMinutes) { - this.activeMinutes = activeMinutes; - } - - public AbstractScheduleShortInfo getSchedule() { - return schedule; - } - - public void setSchedule(AbstractScheduleShortInfo schedule) { - this.schedule = schedule; - } - - public List getTaskgroupPath() { - return taskgroupPath; - } - - public void setTaskgroupPath(List taskgroupPath) { - this.taskgroupPath = taskgroupPath; - } - - public TaskShortInfo getTask() { - return task; - } - - public void setTask(TaskShortInfo task) { - this.task = task; - } -} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleStatus.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleStatus.java deleted file mode 100644 index d412d6d..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleStatus.java +++ /dev/null @@ -1,28 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -public class ScheduleStatus { - - private int activeMinutes; - private boolean missedSchedules; - - public ScheduleStatus(int activeMinutes, boolean missedSchedules) { - this.activeMinutes = activeMinutes; - this.missedSchedules = missedSchedules; - } - - public int getActiveMinutes() { - return activeMinutes; - } - - public void setActiveMinutes(int activeMinutes) { - this.activeMinutes = activeMinutes; - } - - public boolean isMissedSchedules() { - return missedSchedules; - } - - public void setMissedSchedules(boolean missedSchedules) { - this.missedSchedules = missedSchedules; - } -} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/TaskScheduleStopResponse.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/TaskScheduleStopResponse.java deleted file mode 100644 index 460c247..0000000 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/TaskScheduleStopResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package core.api.models.timemanager.taskSchedule; - -public class TaskScheduleStopResponse { - - private int workTime; - - public TaskScheduleStopResponse(int workTime) { - this.workTime = workTime; - } - - public int getWorkTime() { - return workTime; - } - - public void setWorkTime(int workTime) { - this.workTime = workTime; - } -} diff --git a/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java b/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java index 9395be1..a809c32 100644 --- a/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java +++ b/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java @@ -16,30 +16,4 @@ import java.util.Optional; @Repository public interface BasicTaskScheduleRepository extends CrudRepository { - @Modifying - @Transactional - @Query(value = "DELETE FROM BasicTaskSchedule bts WHERE bts.scheduleID = ?1") - void deleteBasicTaskScheduleByID(long id); - - @Modifying - @Transactional - @Query(value = "DELETE FROM BasicTaskSchedule bts WHERE bts.task = ?1") - void deleteAllByTask(Task task); - - @Query(value = "SELECT bts FROM BasicTaskSchedule bts WHERE bts.task.taskgroup.user = ?1") - List findAllByUser(User user); - - @Query(value = "SELECT bts FROM BasicTaskSchedule bts WHERE bts.task.taskgroup.user = ?1 AND bts.scheduleDate = ?2") - List findAllByUserAndDate(User user, LocalDate localDate); - - @Query(value = "SELECT bts FROM BasicTaskSchedule bts WHERE bts.task.taskgroup.user.username = ?1 AND bts.startTime is not null and bts.finishedTime is null") - Optional findActiveTaskSchedule(String username); - - List findAllByStartTimeIsNull(); - - @Query(value = "SELECT bts FROM BasicTaskSchedule bts WHERE bts.task.taskgroup.user = ?1 AND bts.scheduleDate = ?2 AND bts.finishedTime IS NOT NULL") - List findAllFinishedByUserAndDate(User user, LocalDate now); - - @Query(value = "SELECT bts FROM BasicTaskSchedule bts WHERE bts.task.taskgroup.user = ?1 AND bts.startTime IS NULL AND bts.finishedTime IS NULL") - List findAllUnstartedSchedulesOfUser(User user); } diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index bde5b23..c489411 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -1,228 +1,9 @@ package core.services; -import core.api.models.timemanager.taskSchedule.BasicTaskScheduleFieldInfo; -import core.api.models.timemanager.taskSchedule.ForgottenActivity; -import core.entities.User; -import core.entities.timemanager.BasicTaskSchedule; -import core.entities.timemanager.Task; -import core.repositories.UserRepository; -import core.repositories.timemanager.BasicTaskScheduleRepository; -import core.repositories.timemanager.TaskRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; - @Service public class TaskScheduleService { - private final BasicTaskScheduleRepository basicTaskScheduleRepository; - private final TaskRepository taskRepository; - private final UserRepository userRepository; - public TaskScheduleService(@Autowired BasicTaskScheduleRepository basicTaskScheduleRepository, - @Autowired TaskRepository taskRepository, - UserRepository userRepository) { - this.basicTaskScheduleRepository = basicTaskScheduleRepository; - this.taskRepository = taskRepository; - this.userRepository = userRepository; - } - - public ServiceResult createBasicTaskSchedule(Task task, BasicTaskScheduleFieldInfo basicTaskScheduleFieldInfo) { - BasicTaskSchedule basicTaskSchedule = new BasicTaskSchedule(task, basicTaskScheduleFieldInfo.getScheduleDate()); - task.getBasicTaskSchedules().add(basicTaskSchedule); - basicTaskScheduleRepository.save(basicTaskSchedule); - taskRepository.save(task); - return new ServiceResult<>(basicTaskSchedule); - } - - public PermissionResult getSchedulePermissions(long scheduleID, String name) { - Optional basicSchedule = basicTaskScheduleRepository.findById(scheduleID); - return basicSchedule.map(value -> new PermissionResult<>(value, value.getTask().getTaskgroup().getUser().getUsername().equals(name))).orElseGet(() -> - new PermissionResult<>(ServiceExitCode.MISSING_ENTITY)); - } - - public void reschedule(BasicTaskSchedule basicTaskSchedule, BasicTaskScheduleFieldInfo basicTaskScheduleFieldInfo) { - basicTaskSchedule.setScheduleDate(basicTaskScheduleFieldInfo.getScheduleDate()); - basicTaskScheduleRepository.save(basicTaskSchedule); - } - - public void deleteBasicSchedule(BasicTaskSchedule basicTaskSchedule) { - basicTaskScheduleRepository.deleteBasicTaskScheduleByID(basicTaskSchedule.getScheduleID()); - } - - public ServiceResult> loadTodaysSchedule(String username, boolean onlyActivateable) { - Optional user = userRepository.findByUsername(username); - if(user.isEmpty()) { - return new ServiceResult<>(ServiceExitCode.MISSING_ENTITY); - } - - List basicTaskSchedules = basicTaskScheduleRepository.findAllByUserAndDate(user.get(), LocalDate.now()); - List activatableSchedules = new LinkedList<>(); - if(onlyActivateable) { - for (BasicTaskSchedule basicTaskSchedule : basicTaskSchedules) { - if (basicTaskSchedule.isActivateAble()) { - activatableSchedules.add(basicTaskSchedule); - } - } - } - return new ServiceResult<>(activatableSchedules); - } - - public ServiceResult> loadSchedules(String username) { - Optional user = userRepository.findByUsername(username); - return user.map(value -> new ServiceResult<>(basicTaskScheduleRepository.findAllByUser(value))).orElseGet(() -> - new ServiceResult<>(ServiceExitCode.MISSING_ENTITY)); - } - - public ServiceResult scheduleTaskNow(Task task) { - //Check if task has already an active schedule - ServiceResult activeSchedule = getActiveSchedule(task.getTaskgroup().getUser().getUsername()); - if(task.hasActiveSchedule() || activeSchedule.getExitCode() != ServiceExitCode.MISSING_ENTITY) { - return new ServiceResult<>(ServiceExitCode.ENTITY_ALREADY_EXIST); - } else { - BasicTaskSchedule basicTaskSchedule = new BasicTaskSchedule(task, LocalDate.now()); - basicTaskSchedule.setStartTime(LocalDateTime.now()); - task.getBasicTaskSchedules().add(basicTaskSchedule); - basicTaskScheduleRepository.save(basicTaskSchedule); - taskRepository.save(task); - return new ServiceResult<>(basicTaskSchedule); - } - } - - public void deleteScheduleByTask(Task task) { - basicTaskScheduleRepository.deleteAllByTask(task); - } - - public ServiceResult getActiveSchedule(String username) { - Optional activeTaskScheduleResult = basicTaskScheduleRepository.findActiveTaskSchedule(username); - return activeTaskScheduleResult.map(ServiceResult::new).orElseGet(() -> new ServiceResult<>(ServiceExitCode.MISSING_ENTITY)); - } - - public ServiceResult activateSchedule(BasicTaskSchedule taskSchedule) { - //Check if taskSchedule can be started - if(taskSchedule.getStartTime() != null) { - return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION); - } - - if(getActiveSchedule(taskSchedule.getTask().getTaskgroup().getUser().getUsername()).getExitCode() == ServiceExitCode.MISSING_ENTITY) { - taskSchedule.setStartTime(LocalDateTime.now()); - basicTaskScheduleRepository.save(taskSchedule); - return new ServiceResult<>(taskSchedule); - } else { - return new ServiceResult<>(ServiceExitCode.ENTITY_ALREADY_EXIST); - } - } - - public ServiceResult stopSchedule(BasicTaskSchedule taskSchedule, boolean finish) { - if(taskSchedule.getStartTime() == null || taskSchedule.getFinishedTime() != null) { - return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION); - } - - taskSchedule.setFinishedTime(LocalDateTime.now()); - long activeTime = Duration.between(taskSchedule.getStartTime(), taskSchedule.getFinishedTime()).toMinutes(); - long workTime = taskSchedule.getTask().getWorkTime() + activeTime; - taskSchedule.getTask().setWorkTime((int) workTime); - if(finish) { - taskSchedule.getTask().setFinished(true); - } - basicTaskScheduleRepository.save(taskSchedule); - taskRepository.save(taskSchedule.getTask()); - return new ServiceResult<>((int) activeTime); - } - - public int getWorkedMinutes(User user) { - List basicTaskSchedules = basicTaskScheduleRepository.findAllByUser(user); - long workedMinutes = 0; - for(BasicTaskSchedule basicTaskSchedule : basicTaskSchedules) { - if(basicTaskSchedule.getFinishedTime() != null && basicTaskSchedule.getFinishedTime().toLocalDate().isEqual(LocalDate.now())) { - workedMinutes += Duration.between(basicTaskSchedule.getStartTime(), basicTaskSchedule.getFinishedTime()).toMinutes(); - } - } - return (int) workedMinutes; - } - - public boolean isAnyScheduleMissed(User user) { - List unstartedSchedules = basicTaskScheduleRepository.findAllByStartTimeIsNull(); - LocalDate dateReference = LocalDate.now(); - for(BasicTaskSchedule schedule : unstartedSchedules) { - if(schedule.getScheduleDate().isBefore(dateReference)) { - return true; - } - } - return false; - } - - public ServiceResult registerForgottenActivity(Task task, ForgottenActivity forgottenActivity) { - switch (forgottenActivity.getMode()) { - case MANUAL -> { - task.increaseActiveTime(forgottenActivity.getMinutesSpent()); - BasicTaskSchedule basicTaskSchedule = new BasicTaskSchedule(task, LocalDate.now()); - LocalDateTime timeReference = LocalDateTime.now(); - basicTaskSchedule.setStartTime(timeReference.minusMinutes(forgottenActivity.getMinutesSpent())); - basicTaskSchedule.setFinishedTime(timeReference); - task.getBasicTaskSchedules().add(basicTaskSchedule); - basicTaskScheduleRepository.save(basicTaskSchedule); - taskRepository.save(task); - return new ServiceResult<>(forgottenActivity.getMinutesSpent()); - } - case LAST -> { - List schedules = basicTaskScheduleRepository.findAllFinishedByUserAndDate(task.getTaskgroup().getUser(), LocalDate.now()); - if(schedules.isEmpty()) { - return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION); - } else { - LocalDateTime timeReference = LocalDateTime.now(); - BasicTaskSchedule nearestSchedule = null; - long nearestDuration = Long.MAX_VALUE; - for(BasicTaskSchedule schedule : schedules) { - if(nearestSchedule == null) { - nearestSchedule = schedule; - nearestDuration = Duration.between(nearestSchedule.getFinishedTime(), timeReference).getSeconds(); - } else { - long currentDuration = Duration.between(schedule.getFinishedTime(), timeReference).getSeconds(); - if(currentDuration < nearestDuration) { - nearestSchedule = schedule; - nearestDuration = currentDuration; - } - } - } - - int minutesSpent = (int) Duration.between(nearestSchedule.getFinishedTime(), timeReference).toMinutes(); - task.increaseActiveTime(minutesSpent); - BasicTaskSchedule basicTaskSchedule = new BasicTaskSchedule(task, timeReference.toLocalDate()); - basicTaskSchedule.setStartTime(nearestSchedule.getFinishedTime()); - basicTaskSchedule.setFinishedTime(timeReference); - basicTaskScheduleRepository.save(basicTaskSchedule); - taskRepository.save(task); - return new ServiceResult<>(minutesSpent); - } - } - case PLANNED -> { - //Does not make sense until advanced schedule/moderate schedule is implemented - return new ServiceResult<>(0); - } - default -> { - throw new RuntimeException("INVALID MODE"); - } - } - - } - - public List loadMissedSchedules(User user) { - List unstartedSchedules = basicTaskScheduleRepository.findAllUnstartedSchedulesOfUser(user); - LocalDate currentDate = LocalDate.now(); - List missedSchedules = new LinkedList<>(); - for(BasicTaskSchedule schedule : unstartedSchedules) { - if(schedule.getScheduleDate().isBefore(currentDate)) { - missedSchedules.add(schedule); - } - } - return missedSchedules; - } } -- 2.34.1 From 4d1b4a0d9e9c527666062f7175e4da1c8f9b1dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 11 Nov 2023 14:21:19 +0100 Subject: [PATCH 02/18] Get All Schedules of User --- .../api/controller/ScheduleController.java | 23 +++--- .../timemanager/AbstractSchedule.java | 77 ++++++++++++++++++ .../timemanager/AdvancedTaskSchedule.java | 12 +++ .../timemanager/BasicTaskSchedule.java | 79 ++----------------- .../java/core/entities/timemanager/Task.java | 19 +---- .../BasicTaskScheduleRepository.java | 19 ----- .../timemanager/ScheduleRepository.java | 16 ++++ .../core/services/TaskScheduleService.java | 13 +++ .../main/java/core/services/TaskService.java | 9 +-- .../schedules/ScheduleRepositoryTest.java | 35 ++++++++ .../core/schedules/ScheduleServiceTest.java | 49 ++++++++++++ .../test/resources/basicScheduleEntries.sql | 3 + 12 files changed, 229 insertions(+), 125 deletions(-) create mode 100644 backend/src/main/java/core/entities/timemanager/AbstractSchedule.java create mode 100644 backend/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java delete mode 100644 backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java create mode 100644 backend/src/main/java/core/repositories/timemanager/ScheduleRepository.java create mode 100644 backend/src/test/java/core/schedules/ScheduleRepositoryTest.java create mode 100644 backend/src/test/java/core/schedules/ScheduleServiceTest.java create mode 100644 backend/src/test/resources/basicScheduleEntries.sql diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java index 5406dfe..da39359 100644 --- a/backend/src/main/java/core/api/controller/ScheduleController.java +++ b/backend/src/main/java/core/api/controller/ScheduleController.java @@ -1,26 +1,27 @@ package core.api.controller; -import core.api.models.auth.SimpleStatusResponse; -import core.api.models.timemanager.taskSchedule.*; -import core.entities.User; -import core.entities.timemanager.BasicTaskSchedule; -import core.entities.timemanager.ScheduleType; -import core.entities.timemanager.Task; -import core.repositories.UserRepository; -import core.repositories.timemanager.BasicTaskScheduleRepository; -import core.services.*; + +import core.entities.timemanager.AbstractSchedule; +import core.services.TaskScheduleService; import org.springframework.beans.factory.annotation.Autowired; 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.*; +import java.util.List; + @CrossOrigin(origins = "*", maxAge = 3600) @RestController @RequestMapping("/api") public class ScheduleController { + @Autowired private TaskScheduleService taskScheduleService; + @GetMapping("/schedules") + public ResponseEntity loadAllSchedulesOfUser() { + String username = SecurityContextHolder.getContext().getAuthentication().getName(); + List schedules = taskScheduleService.getAllSchedulesOfUser(username); + return ResponseEntity.ok(schedules); + } } diff --git a/backend/src/main/java/core/entities/timemanager/AbstractSchedule.java b/backend/src/main/java/core/entities/timemanager/AbstractSchedule.java new file mode 100644 index 0000000..d04e04f --- /dev/null +++ b/backend/src/main/java/core/entities/timemanager/AbstractSchedule.java @@ -0,0 +1,77 @@ +package core.entities.timemanager; + +import javax.persistence.*; +import java.time.LocalDateTime; +import java.util.Objects; + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name="scheduleType", + discriminatorType = DiscriminatorType.INTEGER) +public abstract class AbstractSchedule { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long scheduleID; + + @ManyToOne + @JoinColumn(referencedColumnName = "taskID", name = "task") + private Task task; + + private LocalDateTime startTime; + private LocalDateTime stopTime; + + public AbstractSchedule() { + } + + public AbstractSchedule(Task task, LocalDateTime startTime, LocalDateTime stopTime) { + this.task = task; + this.startTime = startTime; + this.stopTime = stopTime; + } + + public long getScheduleID() { + return scheduleID; + } + + public void setScheduleID(long scheduleID) { + this.scheduleID = scheduleID; + } + + public Task getTask() { + return task; + } + + public void setTask(Task task) { + this.task = task; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getStopTime() { + return stopTime; + } + + public void setStopTime(LocalDateTime stopTime) { + this.stopTime = stopTime; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AbstractSchedule that = (AbstractSchedule) o; + return scheduleID == that.scheduleID && Objects.equals(task, that.task) && Objects.equals(startTime, that.startTime) && Objects.equals(stopTime, that.stopTime); + } + + @Override + public int hashCode() { + return Objects.hash(scheduleID, task, startTime, stopTime); + } +} diff --git a/backend/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java b/backend/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java new file mode 100644 index 0000000..2f5a0c1 --- /dev/null +++ b/backend/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java @@ -0,0 +1,12 @@ +package core.entities.timemanager; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import java.time.LocalDateTime; +@Entity +@DiscriminatorValue("1") +public class AdvancedTaskSchedule extends AbstractSchedule { + + private LocalDateTime scheduleStart; + private LocalDateTime scheduleEnd; +} diff --git a/backend/src/main/java/core/entities/timemanager/BasicTaskSchedule.java b/backend/src/main/java/core/entities/timemanager/BasicTaskSchedule.java index 00d281e..aab9e9b 100644 --- a/backend/src/main/java/core/entities/timemanager/BasicTaskSchedule.java +++ b/backend/src/main/java/core/entities/timemanager/BasicTaskSchedule.java @@ -6,51 +6,17 @@ import java.time.LocalDateTime; import java.util.Objects; @Entity -@Table(name = "basic_schedules") -public class BasicTaskSchedule { +@DiscriminatorValue("0") +public class BasicTaskSchedule extends AbstractSchedule{ - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private long scheduleID; - - @ManyToOne - @JoinColumn(referencedColumnName = "taskID", name = "task") - private Task task; - - private LocalDate scheduleDate; - private LocalDateTime startTime; - private LocalDateTime finishedTime; - - public BasicTaskSchedule(Task task, LocalDate scheduleDate) { - this.task = task; - this.scheduleDate = scheduleDate; - } + private LocalDate scheduleDate; public BasicTaskSchedule() { } - public void start() { - this.startTime = LocalDateTime.now(); - } - - public void end() { - this.finishedTime = LocalDateTime.now(); - } - - public long getScheduleID() { - return scheduleID; - } - - public void setScheduleID(long scheduleID) { - this.scheduleID = scheduleID; - } - - public Task getTask() { - return task; - } - - public void setTask(Task task) { - this.task = task; + public BasicTaskSchedule(Task task, LocalDateTime startTime, LocalDateTime stopTime, LocalDate scheduleDate) { + super(task, startTime, stopTime); + this.scheduleDate = scheduleDate; } public LocalDate getScheduleDate() { @@ -60,37 +26,4 @@ public class BasicTaskSchedule { public void setScheduleDate(LocalDate scheduleDate) { this.scheduleDate = scheduleDate; } - - public LocalDateTime getStartTime() { - return startTime; - } - - public void setStartTime(LocalDateTime startTime) { - this.startTime = startTime; - } - - public LocalDateTime getFinishedTime() { - return finishedTime; - } - - public void setFinishedTime(LocalDateTime finishedTime) { - this.finishedTime = finishedTime; - } - - public boolean isActivateAble() { - return startTime == null; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - BasicTaskSchedule that = (BasicTaskSchedule) o; - return scheduleID == that.scheduleID; - } - - @Override - public int hashCode() { - return Objects.hash(scheduleID); - } } diff --git a/backend/src/main/java/core/entities/timemanager/Task.java b/backend/src/main/java/core/entities/timemanager/Task.java index 440f59b..4d9271a 100644 --- a/backend/src/main/java/core/entities/timemanager/Task.java +++ b/backend/src/main/java/core/entities/timemanager/Task.java @@ -29,7 +29,7 @@ public class Task { private boolean finished; @OneToMany(mappedBy = "task", cascade = CascadeType.ALL, fetch = FetchType.EAGER) - private List basicTaskSchedules; + private List basicTaskSchedules; private int workTime; @@ -117,27 +117,14 @@ public class Task { this.taskID = taskID; } - public List getBasicTaskSchedules() { + public List getBasicTaskSchedules() { return basicTaskSchedules; } - public void setBasicTaskSchedules(List basicTaskSchedules) { + public void setBasicTaskSchedules(List basicTaskSchedules) { this.basicTaskSchedules = basicTaskSchedules; } - public boolean hasActiveSchedule() { - for(BasicTaskSchedule basicTaskSchedule : basicTaskSchedules) { - if(basicTaskSchedule.getStartTime() != null && basicTaskSchedule.getFinishedTime() == null) { - return true; - } - } - return false; - } - - public void increaseActiveTime(int minutesSpent) { - this.workTime += minutesSpent; - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java b/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java deleted file mode 100644 index a809c32..0000000 --- a/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java +++ /dev/null @@ -1,19 +0,0 @@ -package core.repositories.timemanager; - -import core.entities.User; -import core.entities.timemanager.BasicTaskSchedule; -import core.entities.timemanager.Task; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.CrudRepository; -import org.springframework.stereotype.Repository; - -import javax.transaction.Transactional; -import java.time.LocalDate; -import java.util.List; -import java.util.Optional; - -@Repository -public interface BasicTaskScheduleRepository extends CrudRepository { - -} diff --git a/backend/src/main/java/core/repositories/timemanager/ScheduleRepository.java b/backend/src/main/java/core/repositories/timemanager/ScheduleRepository.java new file mode 100644 index 0000000..c947222 --- /dev/null +++ b/backend/src/main/java/core/repositories/timemanager/ScheduleRepository.java @@ -0,0 +1,16 @@ +package core.repositories.timemanager; + +import core.entities.timemanager.AbstractSchedule; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ScheduleRepository extends CrudRepository { + + @Query(value = "SELECT s FROM AbstractSchedule s WHERE s.task.taskgroup.user.username = ?1") + List findAllByUsername(String username); + +} diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index c489411..a546c36 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -1,9 +1,22 @@ package core.services; +import core.entities.User; +import core.entities.timemanager.AbstractSchedule; +import core.repositories.UserRepository; +import core.repositories.timemanager.ScheduleRepository; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.List; +import java.util.Optional; + @Service public class TaskScheduleService { + @Autowired private ScheduleRepository scheduleRepository; + @Autowired private UserRepository userRepository; + public List getAllSchedulesOfUser(String username) { + return scheduleRepository.findAllByUsername(username); + } } diff --git a/backend/src/main/java/core/services/TaskService.java b/backend/src/main/java/core/services/TaskService.java index eaa1f24..1df8378 100644 --- a/backend/src/main/java/core/services/TaskService.java +++ b/backend/src/main/java/core/services/TaskService.java @@ -2,17 +2,14 @@ package core.services; 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.BasicTaskScheduleRepository; import core.repositories.timemanager.TaskRepository; import core.repositories.timemanager.TaskgroupRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.*; @Service @@ -93,7 +90,7 @@ public class TaskService { } public void deleteTask(Task task) { - taskScheduleService.deleteScheduleByTask(task); + //taskScheduleService.deleteScheduleByTask(task); taskRepository.deleteByTaskID(task.getTaskID()); } @@ -106,7 +103,7 @@ public class TaskService { task.finish(); taskRepository.save(task); - List removedBasicTaskSchedules = new LinkedList<>(); + /*List removedBasicTaskSchedules = new LinkedList<>(); for(BasicTaskSchedule basicTaskSchedule : task.getBasicTaskSchedules()) { if(basicTaskSchedule.getStartTime() == null) { removedBasicTaskSchedules.add(basicTaskSchedule); @@ -120,7 +117,7 @@ public class TaskService { task.getBasicTaskSchedules().remove(deletedTaskSchedule); taskRepository.save(task); taskScheduleService.deleteBasicSchedule(deletedTaskSchedule); - } + }*/ } public List loadAllTasks(String username, TaskScope scope) { diff --git a/backend/src/test/java/core/schedules/ScheduleRepositoryTest.java b/backend/src/test/java/core/schedules/ScheduleRepositoryTest.java new file mode 100644 index 0000000..c113d3e --- /dev/null +++ b/backend/src/test/java/core/schedules/ScheduleRepositoryTest.java @@ -0,0 +1,35 @@ +package core.schedules; + +import core.entities.User; +import core.repositories.timemanager.ScheduleRepository; +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 static org.junit.jupiter.api.Assertions.assertEquals; + +@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(2, scheduleRepository.findAllByUsername(referenceUser_1.getUsername()).size()); + } +} diff --git a/backend/src/test/java/core/schedules/ScheduleServiceTest.java b/backend/src/test/java/core/schedules/ScheduleServiceTest.java new file mode 100644 index 0000000..1d83cfb --- /dev/null +++ b/backend/src/test/java/core/schedules/ScheduleServiceTest.java @@ -0,0 +1,49 @@ +package core.schedules; + +import core.entities.timemanager.AbstractSchedule; +import core.repositories.timemanager.TaskgroupRepository; +import core.services.TaskScheduleService; +import core.services.TaskgroupService; +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.util.List; + +import static org.hibernate.validator.internal.util.Contracts.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@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(2, result_1.size()); + assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 1L))); + assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 2L))); + } +} diff --git a/backend/src/test/resources/basicScheduleEntries.sql b/backend/src/test/resources/basicScheduleEntries.sql new file mode 100644 index 0000000..894eab7 --- /dev/null +++ b/backend/src/test/resources/basicScheduleEntries.sql @@ -0,0 +1,3 @@ +INSERT INTO abstract_schedule (schedule_type, scheduleid, start_time, stop_time, schedule_date, task, schedule_end, schedule_start) +VALUES (0, 1, null, null, '2023-11-11', 1, null, null), + (0, 2, null, null, '2023-11-11', 2, null, null); \ No newline at end of file -- 2.34.1 From dcc488fcedea4acf03ae3f8b3e5d9e14c364eae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 11 Nov 2023 15:00:36 +0100 Subject: [PATCH 03/18] Get All Schedules of Task + create Basic Schedule --- .../api/controller/ScheduleController.java | 46 ++++++++++++++++++- .../taskSchedule/BasicScheduleFieldInfo.java | 25 ++++++++++ .../taskSchedule/BasicScheduleInfo.java | 18 ++++++++ .../taskSchedule/ScheduleFieldInfo.java | 4 ++ .../taskSchedule/ScheduleInfo.java | 38 +++++++++++++++ .../taskSchedule/ScheduleType.java | 8 ++++ .../timemanager/AbstractSchedule.java | 16 +++++-- .../timemanager/AdvancedTaskSchedule.java | 7 +++ .../timemanager/BasicTaskSchedule.java | 31 +++++++++++++ .../core/services/TaskScheduleService.java | 16 +++++++ .../core/schedules/ScheduleServiceTest.java | 29 ++++++++++++ 11 files changed, 232 insertions(+), 6 deletions(-) create mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleFieldInfo.java create mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleInfo.java create mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleFieldInfo.java create mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleInfo.java create mode 100644 backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleType.java diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java index da39359..6e8abb6 100644 --- a/backend/src/main/java/core/api/controller/ScheduleController.java +++ b/backend/src/main/java/core/api/controller/ScheduleController.java @@ -1,13 +1,20 @@ package core.api.controller; +import core.api.models.auth.SimpleStatusResponse; +import core.api.models.timemanager.taskSchedule.BasicScheduleFieldInfo; +import core.api.models.timemanager.taskSchedule.BasicScheduleInfo; +import core.api.models.timemanager.taskSchedule.ScheduleFieldInfo; import core.entities.timemanager.AbstractSchedule; -import core.services.TaskScheduleService; +import core.entities.timemanager.Task; +import core.services.*; 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.List; @@ -17,11 +24,46 @@ import java.util.List; public class ScheduleController { @Autowired private TaskScheduleService taskScheduleService; + @Autowired private TaskService taskService; @GetMapping("/schedules") public ResponseEntity loadAllSchedulesOfUser() { String username = SecurityContextHolder.getContext().getAuthentication().getName(); List schedules = taskScheduleService.getAllSchedulesOfUser(username); - return ResponseEntity.ok(schedules); + return ResponseEntity.ok(schedules.stream().map(AbstractSchedule::toScheduleInfo).toList()); + } + + @GetMapping("/schedules/{taskID}") + public ResponseEntity loadAllSchedulesOfTask(@PathVariable long taskID) { + PermissionResult permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); + if(permissionResult.isHasPermissions()) { + return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); + } + + if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { + return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); + } + + List taskSchedules = permissionResult.getResult().getBasicTaskSchedules(); + return ResponseEntity.ok(taskSchedules.stream().map(AbstractSchedule::toScheduleInfo).toList()); + } + + @PutMapping("/schedules/{taskID}") + public ResponseEntity createSchedule(@PathVariable long taskID, @RequestBody @Valid ScheduleFieldInfo scheduleFieldInfo) { + PermissionResult permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); + if(permissionResult.isHasPermissions()) { + return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); + } + + if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { + return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); + } + + if(scheduleFieldInfo instanceof BasicScheduleFieldInfo) { + ServiceResult scheduleResult = taskScheduleService.scheduleBasic(permissionResult.getResult(), (BasicScheduleFieldInfo) scheduleFieldInfo); + return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo()); + } else { + return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); + } } } diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleFieldInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleFieldInfo.java new file mode 100644 index 0000000..8f7a90a --- /dev/null +++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleFieldInfo.java @@ -0,0 +1,25 @@ +package core.api.models.timemanager.taskSchedule; + +import javax.validation.constraints.NotNull; +import java.time.LocalDate; + +public class BasicScheduleFieldInfo extends ScheduleFieldInfo{ + + @NotNull + private LocalDate scheduleDate; + + public BasicScheduleFieldInfo(LocalDate localDate) { + this.scheduleDate = localDate; + } + + public BasicScheduleFieldInfo() { + } + + public LocalDate getScheduleDate() { + return scheduleDate; + } + + public void setScheduleDate(LocalDate scheduleDate) { + this.scheduleDate = scheduleDate; + } +} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleInfo.java new file mode 100644 index 0000000..aa97dd9 --- /dev/null +++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/BasicScheduleInfo.java @@ -0,0 +1,18 @@ +package core.api.models.timemanager.taskSchedule; + +import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; +import core.entities.timemanager.Task; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +public class BasicScheduleInfo extends ScheduleInfo{ + + private LocalDate scheduleDate; + public BasicScheduleInfo(long scheduleID, ScheduleType scheduleType, LocalDateTime startTime, LocalDateTime stopTime, int activeMinutes, Task task, List taskgroupPath) { + super(scheduleID, scheduleType, startTime, stopTime, activeMinutes, task, taskgroupPath); + } + + +} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleFieldInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleFieldInfo.java new file mode 100644 index 0000000..d7dba9c --- /dev/null +++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleFieldInfo.java @@ -0,0 +1,4 @@ +package core.api.models.timemanager.taskSchedule; + +public abstract class ScheduleFieldInfo { +} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleInfo.java new file mode 100644 index 0000000..d74fe07 --- /dev/null +++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleInfo.java @@ -0,0 +1,38 @@ +package core.api.models.timemanager.taskSchedule; + +import com.fasterxml.jackson.annotation.JsonProperty; +import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; +import core.api.models.timemanager.tasks.TaskShortInfo; +import core.entities.timemanager.Task; +import core.entities.timemanager.Taskgroup; + +import java.time.LocalDateTime; +import java.util.List; + +public abstract class ScheduleInfo { + + @JsonProperty + private long scheduleID; + @JsonProperty + private ScheduleType scheduleType; + @JsonProperty + private LocalDateTime startTime; + @JsonProperty + private LocalDateTime stopTime; + @JsonProperty + private int activeMinutes; + @JsonProperty + private TaskShortInfo task; + @JsonProperty + private List taskgroupPath; + + public ScheduleInfo(long scheduleID, ScheduleType scheduleType, LocalDateTime startTime, LocalDateTime stopTime, int activeMinutes, Task task, List taskgroupPath) { + this.scheduleID = scheduleID; + this.scheduleType = scheduleType; + this.startTime = startTime; + this.stopTime = stopTime; + this.activeMinutes = activeMinutes; + this.task = new TaskShortInfo(task); + this.taskgroupPath = taskgroupPath; + } +} diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleType.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleType.java new file mode 100644 index 0000000..f86a82c --- /dev/null +++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleType.java @@ -0,0 +1,8 @@ +package core.api.models.timemanager.taskSchedule; + +public enum ScheduleType { + + BASIC, + MODERATE, + ADVANCED; +} diff --git a/backend/src/main/java/core/entities/timemanager/AbstractSchedule.java b/backend/src/main/java/core/entities/timemanager/AbstractSchedule.java index d04e04f..fcce4d4 100644 --- a/backend/src/main/java/core/entities/timemanager/AbstractSchedule.java +++ b/backend/src/main/java/core/entities/timemanager/AbstractSchedule.java @@ -1,5 +1,7 @@ package core.entities.timemanager; +import core.api.models.timemanager.taskSchedule.ScheduleInfo; + import javax.persistence.*; import java.time.LocalDateTime; import java.util.Objects; @@ -12,14 +14,14 @@ public abstract class AbstractSchedule { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private long scheduleID; + protected long scheduleID; @ManyToOne @JoinColumn(referencedColumnName = "taskID", name = "task") - private Task task; + protected Task task; - private LocalDateTime startTime; - private LocalDateTime stopTime; + protected LocalDateTime startTime; + protected LocalDateTime stopTime; public AbstractSchedule() { } @@ -30,6 +32,10 @@ public abstract class AbstractSchedule { this.stopTime = stopTime; } + public AbstractSchedule(Task task) { + this.task = task; + } + public long getScheduleID() { return scheduleID; } @@ -74,4 +80,6 @@ public abstract class AbstractSchedule { public int hashCode() { return Objects.hash(scheduleID, task, startTime, stopTime); } + + public abstract ScheduleInfo toScheduleInfo(); } diff --git a/backend/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java b/backend/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java index 2f5a0c1..43f0735 100644 --- a/backend/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java +++ b/backend/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java @@ -1,5 +1,7 @@ package core.entities.timemanager; +import core.api.models.timemanager.taskSchedule.ScheduleInfo; + import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; import java.time.LocalDateTime; @@ -9,4 +11,9 @@ public class AdvancedTaskSchedule extends AbstractSchedule { private LocalDateTime scheduleStart; private LocalDateTime scheduleEnd; + + @Override + public ScheduleInfo toScheduleInfo() { + return null; + } } diff --git a/backend/src/main/java/core/entities/timemanager/BasicTaskSchedule.java b/backend/src/main/java/core/entities/timemanager/BasicTaskSchedule.java index aab9e9b..a861bab 100644 --- a/backend/src/main/java/core/entities/timemanager/BasicTaskSchedule.java +++ b/backend/src/main/java/core/entities/timemanager/BasicTaskSchedule.java @@ -1,8 +1,16 @@ package core.entities.timemanager; +import core.api.models.timemanager.taskSchedule.BasicScheduleInfo; +import core.api.models.timemanager.taskSchedule.ScheduleInfo; +import core.api.models.timemanager.taskSchedule.ScheduleType; +import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; +import core.api.models.timemanager.tasks.TaskEntityInfo; + import javax.persistence.*; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.List; import java.util.Objects; @Entity @@ -19,6 +27,11 @@ public class BasicTaskSchedule extends AbstractSchedule{ this.scheduleDate = scheduleDate; } + public BasicTaskSchedule(Task task, LocalDate scheduleDate) { + super(task); + this.scheduleDate = scheduleDate; + } + public LocalDate getScheduleDate() { return scheduleDate; } @@ -26,4 +39,22 @@ public class BasicTaskSchedule extends AbstractSchedule{ public void setScheduleDate(LocalDate scheduleDate) { this.scheduleDate = scheduleDate; } + + public ScheduleInfo toScheduleInfo() { + int activeMinutes = calcActiveMinutes(); + List taskgroupEntityInfos = Taskgroup.getAncestorList(task.getTaskgroup()).stream().map(TaskgroupEntityInfo::new).toList(); + return new BasicScheduleInfo(scheduleID, ScheduleType.BASIC, startTime, stopTime, activeMinutes, task, taskgroupEntityInfos); + } + + public int calcActiveMinutes() { + if(startTime == null) { + return 0; + } else if(stopTime == null) { + Duration duration = Duration.between(startTime, LocalDateTime.now()); + return (int) duration.toMinutes(); + } else { + Duration duration = Duration.between(startTime, stopTime); + return (int) duration.toMinutes(); + } + } } diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index a546c36..cc8242c 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -1,12 +1,17 @@ package core.services; +import core.api.models.timemanager.taskSchedule.BasicScheduleFieldInfo; +import core.api.models.timemanager.taskSchedule.ScheduleFieldInfo; import core.entities.User; import core.entities.timemanager.AbstractSchedule; +import core.entities.timemanager.BasicTaskSchedule; +import core.entities.timemanager.Task; import core.repositories.UserRepository; import core.repositories.timemanager.ScheduleRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.time.LocalDate; import java.util.List; import java.util.Optional; @@ -19,4 +24,15 @@ public class TaskScheduleService { public List getAllSchedulesOfUser(String username) { return scheduleRepository.findAllByUsername(username); } + + public ServiceResult scheduleBasic(Task task, BasicScheduleFieldInfo scheduleFieldInfo) { + if(task.isFinished() || scheduleFieldInfo.getScheduleDate().isBefore(LocalDate.now())) { + return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION); + } + + BasicTaskSchedule basicTaskSchedule = new BasicTaskSchedule(task, scheduleFieldInfo.getScheduleDate()); + scheduleRepository.save(basicTaskSchedule); + + return new ServiceResult<>(basicTaskSchedule); + } } diff --git a/backend/src/test/java/core/schedules/ScheduleServiceTest.java b/backend/src/test/java/core/schedules/ScheduleServiceTest.java index 1d83cfb..356c8f6 100644 --- a/backend/src/test/java/core/schedules/ScheduleServiceTest.java +++ b/backend/src/test/java/core/schedules/ScheduleServiceTest.java @@ -1,7 +1,13 @@ package core.schedules; +import core.api.models.timemanager.taskSchedule.BasicScheduleFieldInfo; +import core.api.models.timemanager.taskSchedule.BasicScheduleInfo; import core.entities.timemanager.AbstractSchedule; +import core.entities.timemanager.BasicTaskSchedule; +import core.entities.timemanager.Task; import core.repositories.timemanager.TaskgroupRepository; +import core.services.ServiceExitCode; +import core.services.ServiceResult; import core.services.TaskScheduleService; import core.services.TaskgroupService; import org.junit.jupiter.api.Test; @@ -13,8 +19,10 @@ 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.hibernate.validator.internal.util.Contracts.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -46,4 +54,25 @@ public class ScheduleServiceTest { assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 1L))); assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 2L))); } + + @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(); + } } -- 2.34.1 From dadb1204e8e1eae5ff3686329d26414d9d73f28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 11 Nov 2023 15:28:10 +0100 Subject: [PATCH 04/18] Refactor /schedules and /schedules/{taskID} endpoints (get + put) --- frontend/src/api/.openapi-generator/FILES | 2 + frontend/src/api/api/schedule.service.ts | 161 +++++++++--------- frontend/src/api/model/basicScheduleInfo.ts | 52 ++++++ .../src/api/model/basicScheduleInfoAllOf.ts | 17 ++ frontend/src/api/model/models.ts | 2 + frontend/src/api/model/scheduleInfo.ts | 2 - .../missed-schedules.component.html | 2 +- .../missed-schedules.component.ts | 6 +- .../basic-scheduler.component.ts | 12 +- .../schedule-dashboard.component.html | 16 +- .../schedule-dashboard.component.ts | 18 +- .../scheduler/scheduler.component.ts | 33 ++-- openapi.yaml | 34 ++-- 13 files changed, 224 insertions(+), 133 deletions(-) create mode 100644 frontend/src/api/model/basicScheduleInfo.ts create mode 100644 frontend/src/api/model/basicScheduleInfoAllOf.ts diff --git a/frontend/src/api/.openapi-generator/FILES b/frontend/src/api/.openapi-generator/FILES index 51b9f45..c190ae0 100644 --- a/frontend/src/api/.openapi-generator/FILES +++ b/frontend/src/api/.openapi-generator/FILES @@ -16,6 +16,8 @@ index.ts model/accountDeleteRequest.ts model/basicScheduleEntityInfo.ts model/basicScheduleFieldInfo.ts +model/basicScheduleInfo.ts +model/basicScheduleInfoAllOf.ts model/eMailChangeRequest.ts model/forgottenActivityRequest.ts model/inlineResponse200.ts diff --git a/frontend/src/api/api/schedule.service.ts b/frontend/src/api/api/schedule.service.ts index e19c1ef..d686ebc 100644 --- a/frontend/src/api/api/schedule.service.ts +++ b/frontend/src/api/api/schedule.service.ts @@ -18,7 +18,6 @@ import { HttpClient, HttpHeaders, HttpParams, import { CustomHttpParameterCodec } from '../encoder'; import { Observable } from 'rxjs'; -import { BasicScheduleEntityInfo } from '../model/models'; import { BasicScheduleFieldInfo } from '../model/models'; import { ForgottenActivityRequest } from '../model/models'; import { ScheduleActivateInfo } from '../model/models'; @@ -626,76 +625,6 @@ export class ScheduleService { ); } - /** - * creates basic schedule for task - * creates a basic schedule for a task - * @param taskID internal id of task - * @param basicScheduleFieldInfo - * @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 schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; - public schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; - public schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; - public schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { - if (taskID === null || taskID === undefined) { - throw new Error('Required parameter taskID was null or undefined when calling schedulesTaskIDBasicPut.'); - } - - 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.put(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(taskID))}/basic`, - basicScheduleFieldInfo, - { - context: localVarHttpContext, - responseType: responseType_, - withCredentials: this.configuration.withCredentials, - headers: localVarHeaders, - observe: observe, - reportProgress: reportProgress - } - ); - } - /** * registers forgotten schedule * Registers forgotten schedule @@ -766,6 +695,65 @@ export class ScheduleService { ); } + /** + * gets schedules of task + * gets schedules of task + * @param taskID internal id of task + * @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 schedulesTaskIDGet(taskID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesTaskIDGet(taskID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; + public schedulesTaskIDGet(taskID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; + public schedulesTaskIDGet(taskID: number, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + if (taskID === null || taskID === undefined) { + throw new Error('Required parameter taskID was null or undefined when calling schedulesTaskIDGet.'); + } + + 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}/schedules/${encodeURIComponent(String(taskID))}`, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + /** * schedule task now * schedule task now @@ -827,22 +815,19 @@ export class ScheduleService { } /** - * gets schedules of task - * gets schedules of task + * creates basic schedule for task + * creates a basic schedule for a task * @param taskID internal id of task - * @param scheduleType internal id of task + * @param basicScheduleFieldInfo * @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 schedulesTaskIDScheduleTypeGet(taskID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; - public schedulesTaskIDScheduleTypeGet(taskID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; - public schedulesTaskIDScheduleTypeGet(taskID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; - public schedulesTaskIDScheduleTypeGet(taskID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + public schedulesTaskIDPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public schedulesTaskIDPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesTaskIDPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesTaskIDPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { if (taskID === null || taskID === undefined) { - throw new Error('Required parameter taskID was null or undefined when calling schedulesTaskIDScheduleTypeGet.'); - } - if (scheduleType === null || scheduleType === undefined) { - throw new Error('Required parameter scheduleType was null or undefined when calling schedulesTaskIDScheduleTypeGet.'); + throw new Error('Required parameter taskID was null or undefined when calling schedulesTaskIDPut.'); } let localVarHeaders = this.defaultHeaders; @@ -872,12 +857,22 @@ export class ScheduleService { } + // 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.get>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(taskID))}/${encodeURIComponent(String(scheduleType))}`, + return this.httpClient.put(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(taskID))}`, + basicScheduleFieldInfo, { context: localVarHttpContext, responseType: responseType_, diff --git a/frontend/src/api/model/basicScheduleInfo.ts b/frontend/src/api/model/basicScheduleInfo.ts new file mode 100644 index 0000000..6cf4391 --- /dev/null +++ b/frontend/src/api/model/basicScheduleInfo.ts @@ -0,0 +1,52 @@ +/** + * 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. + */ +import { BasicScheduleInfoAllOf } from './basicScheduleInfoAllOf'; +import { TaskgroupEntityInfo } from './taskgroupEntityInfo'; +import { TaskShortInfo } from './taskShortInfo'; +import { ScheduleInfo } from './scheduleInfo'; + + +export interface BasicScheduleInfo { + /** + * internal id of schedule + */ + scheduleID: number; + /** + * type of schedule + */ + scheduleType: BasicScheduleInfo.ScheduleTypeEnum; + /** + * date on which the task schedule was started + */ + startTime: string; + /** + * date on which the tasks schedule was finished + */ + finishedTime?: string; + /** + * number in minutes that the schedule was active + */ + activeMinutes: number; + task: TaskShortInfo; + taskgroupPath: Array; + scheduleDate: string; +} +export namespace BasicScheduleInfo { + export type ScheduleTypeEnum = 'BASIC' | 'MODERATE' | 'ADVANCED'; + export const ScheduleTypeEnum = { + Basic: 'BASIC' as ScheduleTypeEnum, + Moderate: 'MODERATE' as ScheduleTypeEnum, + Advanced: 'ADVANCED' as ScheduleTypeEnum + }; +} + + diff --git a/frontend/src/api/model/basicScheduleInfoAllOf.ts b/frontend/src/api/model/basicScheduleInfoAllOf.ts new file mode 100644 index 0000000..ed13196 --- /dev/null +++ b/frontend/src/api/model/basicScheduleInfoAllOf.ts @@ -0,0 +1,17 @@ +/** + * 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 BasicScheduleInfoAllOf { + scheduleDate: string; +} + diff --git a/frontend/src/api/model/models.ts b/frontend/src/api/model/models.ts index 0515444..26a3e14 100644 --- a/frontend/src/api/model/models.ts +++ b/frontend/src/api/model/models.ts @@ -1,6 +1,8 @@ export * from './accountDeleteRequest'; export * from './basicScheduleEntityInfo'; export * from './basicScheduleFieldInfo'; +export * from './basicScheduleInfo'; +export * from './basicScheduleInfoAllOf'; export * from './eMailChangeRequest'; export * from './forgottenActivityRequest'; export * from './inlineResponse200'; diff --git a/frontend/src/api/model/scheduleInfo.ts b/frontend/src/api/model/scheduleInfo.ts index a9deba8..9f09ca6 100644 --- a/frontend/src/api/model/scheduleInfo.ts +++ b/frontend/src/api/model/scheduleInfo.ts @@ -9,7 +9,6 @@ * https://openapi-generator.tech * Do not edit the class manually. */ -import { BasicScheduleFieldInfo } from './basicScheduleFieldInfo'; import { TaskgroupEntityInfo } from './taskgroupEntityInfo'; import { TaskShortInfo } from './taskShortInfo'; @@ -35,7 +34,6 @@ export interface ScheduleInfo { * number in minutes that the schedule was active */ activeMinutes: number; - schedule: BasicScheduleFieldInfo; task: TaskShortInfo; taskgroupPath: Array; } diff --git a/frontend/src/app/missed-schedules/missed-schedules.component.html b/frontend/src/app/missed-schedules/missed-schedules.component.html index ad49ce8..b7ba6b2 100644 --- a/frontend/src/app/missed-schedules/missed-schedules.component.html +++ b/frontend/src/app/missed-schedules/missed-schedules.component.html @@ -13,7 +13,7 @@
-

Originally planned: {{schedule.schedule.scheduleDate}}

+

Originally planned: {{toBasicSchedule(schedule).scheduleDate}}

- + +
+

{{ toBasicSchedule(schedule).scheduleDate | date:'EEEE, d MMM. y'}}

+
+ + +
-
+ + + diff --git a/frontend/src/app/schedules/schedule-dashboard/schedule-dashboard.component.ts b/frontend/src/app/schedules/schedule-dashboard/schedule-dashboard.component.ts index 82de4b0..6ce456a 100644 --- a/frontend/src/app/schedules/schedule-dashboard/schedule-dashboard.component.ts +++ b/frontend/src/app/schedules/schedule-dashboard/schedule-dashboard.component.ts @@ -1,5 +1,11 @@ import {Component, Input, OnInit} from '@angular/core'; -import {BasicScheduleEntityInfo, ScheduleService, TaskEntityInfo, TaskgroupEntityInfo} from "../../../api"; +import { + BasicScheduleEntityInfo, BasicScheduleInfo, + ScheduleInfo, + ScheduleService, + TaskEntityInfo, + TaskgroupEntityInfo +} from "../../../api"; import {MatSnackBar} from "@angular/material/snack-bar"; @Component({ @@ -12,7 +18,7 @@ export class ScheduleDashboardComponent implements OnInit{ @Input('taskgroup') taskgroup: TaskgroupEntityInfo | undefined @Input('task') task: TaskEntityInfo | undefined - schedules: BasicScheduleEntityInfo[] = [] + schedules: ScheduleInfo[] = [] constructor(private scheduleService: ScheduleService, private snackbar: MatSnackBar) { @@ -20,7 +26,7 @@ export class ScheduleDashboardComponent implements OnInit{ } ngOnInit() { - this.scheduleService.schedulesTaskIDScheduleTypeGet(this.task!.taskID, "BASIC").subscribe({ + this.scheduleService.schedulesTaskIDGet(this.task!.taskID).subscribe({ next: resp => { this.schedules = resp; } @@ -31,7 +37,7 @@ export class ScheduleDashboardComponent implements OnInit{ //todo } - deleteSchedule(deletedSchedule: BasicScheduleEntityInfo) { + deleteSchedule(deletedSchedule: ScheduleInfo) { this.scheduleService.schedulesScheduleIDScheduleTypeDelete(deletedSchedule.scheduleID, 'BASIC').subscribe({ next: resp => { this.schedules = this.schedules.filter(schedule => schedule.scheduleID !== deletedSchedule.scheduleID); @@ -47,4 +53,8 @@ export class ScheduleDashboardComponent implements OnInit{ } }) } + + toBasicSchedule(schedule: ScheduleInfo) { + return schedule as BasicScheduleInfo + } } diff --git a/frontend/src/app/schedules/scheduler/scheduler.component.ts b/frontend/src/app/schedules/scheduler/scheduler.component.ts index a5aea85..6d5755f 100644 --- a/frontend/src/app/schedules/scheduler/scheduler.component.ts +++ b/frontend/src/app/schedules/scheduler/scheduler.component.ts @@ -1,7 +1,7 @@ import {Component, OnInit, ViewChild} from '@angular/core'; import {NavigationLink, NavigationLinkListComponent} from "../../navigation-link-list/navigation-link-list.component"; import { - BasicScheduleEntityInfo, ScheduleService, + BasicScheduleEntityInfo, BasicScheduleInfo, ScheduleService, TaskEntityInfo, TaskgroupEntityInfo, TaskgroupService, @@ -136,26 +136,33 @@ export class SchedulerComponent implements OnInit{ fetschSchedules() { this.scheduleService.schedulesGet().subscribe({ next: resp => { - resp.forEach(schedule => { - let color: EventColor = colors['red'] - if(schedule.scheduleID === this.scheduleID) { - color = colors['yellow'] + resp.forEach(abstractSchedule => { + if(abstractSchedule.scheduleType == 'BASIC') { + this.handleFetchedBasicSchedule(abstractSchedule as BasicScheduleInfo) } - if(schedule.scheduleType === 'BASIC') { - this.events.push({ - start: new Date(schedule.schedule.scheduleDate), - title: this.computeTaskPath(schedule.taskgroupPath, schedule.task), - color: color, - allDay: true, - }) - } }) this.refresh.next(); } }) } + handleFetchedBasicSchedule(schedule: BasicScheduleInfo) { + let color: EventColor = colors['red'] + if(schedule.scheduleID === this.scheduleID) { + color = colors['yellow'] + } + + if(schedule.scheduleType === 'BASIC') { + this.events.push({ + start: new Date(schedule.scheduleDate), + title: this.computeTaskPath(schedule.taskgroupPath, schedule.task), + color: color, + allDay: true, + }) + } + } + eventClicked({ event }: { event: CalendarEvent }): void { this.router.navigateByUrl("/taskgroups/" + this.taskgroupID.toString() + "/tasks/" + this.task!.taskID ) } diff --git a/openapi.yaml b/openapi.yaml index 7137880..f0e2f4b 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1270,7 +1270,7 @@ paths: items: $ref: '#/components/schemas/ScheduleInfo' - /schedules/{taskID}/{scheduleType}: + /schedules/{taskID}: get: security: - API_TOKEN: [] @@ -1286,16 +1286,6 @@ paths: schema: type: number example: 1 - - name: scheduleType - in: path - description: internal id of task - required: true - schema: - type: string - enum: - - BASIC - - MODERATE - - ADVANCED responses: 200: description: operation successfull @@ -1304,7 +1294,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/BasicScheduleEntityInfo' + $ref: '#/components/schemas/ScheduleInfo' 403: description: No permission content: @@ -1319,7 +1309,6 @@ paths: schema: type: object $ref: "#/components/schemas/SimpleStatusResponse" - /schedules/{taskID}/basic: put: security: - API_TOKEN: [] @@ -1347,7 +1336,7 @@ paths: application/json: schema: type: object - $ref: '#/components/schemas/BasicScheduleEntityInfo' + $ref: '#/components/schemas/ScheduleInfo' 403: description: No permission content: @@ -2182,7 +2171,6 @@ components: - startTime - finishTime - activeMinutes - - schedule - task - taskgroupPath additionalProperties: false @@ -2211,10 +2199,6 @@ components: type: number description: number in minutes that the schedule was active example: 10 - schedule: - type: object - oneOf: - - $ref: '#/components/schemas/BasicScheduleFieldInfo' task: type: object $ref: '#/components/schemas/TaskShortInfo' @@ -2222,7 +2206,17 @@ components: type: array items: $ref: '#/components/schemas/TaskgroupEntityInfo' - + BasicScheduleInfo: + allOf: + - $ref: '#/components/schemas/ScheduleInfo' + - type: object + required: + - scheduleDate + additionalProperties: false + properties: + scheduleDate: + type: string + format: date TaskShortInfo: required: - taskID -- 2.34.1 From e36bbb0d659364b84af36f5fc3770f031fd4bd0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 11 Nov 2023 15:50:14 +0100 Subject: [PATCH 05/18] Basic Reschedule --- .../api/controller/ScheduleController.java | 24 +++++++++++++++++ .../core/services/TaskScheduleService.java | 16 ++++++++++++ .../core/schedules/ScheduleServiceTest.java | 26 ++++++++++++++++--- .../test/resources/basicScheduleEntries.sql | 4 +-- 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java index 6e8abb6..e6e1528 100644 --- a/backend/src/main/java/core/api/controller/ScheduleController.java +++ b/backend/src/main/java/core/api/controller/ScheduleController.java @@ -6,6 +6,7 @@ import core.api.models.timemanager.taskSchedule.BasicScheduleFieldInfo; import core.api.models.timemanager.taskSchedule.BasicScheduleInfo; import core.api.models.timemanager.taskSchedule.ScheduleFieldInfo; import core.entities.timemanager.AbstractSchedule; +import core.entities.timemanager.BasicTaskSchedule; import core.entities.timemanager.Task; import core.services.*; import org.springframework.beans.factory.annotation.Autowired; @@ -66,4 +67,27 @@ public class ScheduleController { return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); } } + + @PostMapping("/schedules/{scheduleID}") + public ResponseEntity editSchedule(@PathVariable long scheduleID, @RequestBody @Valid ScheduleFieldInfo scheduleFieldInfo) { + PermissionResult permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); + if(permissionResult.isHasPermissions()) { + return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); + } + + if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { + return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); + } + + if(permissionResult.getResult() instanceof BasicTaskSchedule && scheduleFieldInfo instanceof BasicScheduleFieldInfo) { + ServiceResult updatedSchedule = taskScheduleService.editBasicSchedule((BasicTaskSchedule) permissionResult.getResult(), (BasicScheduleFieldInfo) scheduleFieldInfo); + if(updatedSchedule.getExitCode() == ServiceExitCode.INVALID_OPERATION) { + return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); + } else { + return ResponseEntity.ok(updatedSchedule.getResult().toScheduleInfo()); + } + } + + return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); + } } diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index cc8242c..1f11bd6 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -1,6 +1,7 @@ package core.services; import core.api.models.timemanager.taskSchedule.BasicScheduleFieldInfo; +import core.api.models.timemanager.taskSchedule.BasicScheduleInfo; import core.api.models.timemanager.taskSchedule.ScheduleFieldInfo; import core.entities.User; import core.entities.timemanager.AbstractSchedule; @@ -35,4 +36,19 @@ public class TaskScheduleService { return new ServiceResult<>(basicTaskSchedule); } + + public PermissionResult getSchedulePermissions(long scheduleID, String username) { + Optional abstractSchedule = scheduleRepository.findById(scheduleID); + return abstractSchedule.map(schedule -> new PermissionResult<>(schedule, schedule.getTask().getTaskgroup().getUser().getUsername().equals(username))).orElseGet(() -> new PermissionResult<>(ServiceExitCode.MISSING_ENTITY)); + } + + public ServiceResult editBasicSchedule(BasicTaskSchedule schedule, BasicScheduleFieldInfo scheduleFieldInfo) { + if(schedule.getTask().isFinished() || scheduleFieldInfo.getScheduleDate().isBefore(LocalDate.now())) { + return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION); + } + + schedule.setScheduleDate(scheduleFieldInfo.getScheduleDate()); + scheduleRepository.save(schedule); + return new ServiceResult<>(schedule); + } } diff --git a/backend/src/test/java/core/schedules/ScheduleServiceTest.java b/backend/src/test/java/core/schedules/ScheduleServiceTest.java index 356c8f6..edc4ef7 100644 --- a/backend/src/test/java/core/schedules/ScheduleServiceTest.java +++ b/backend/src/test/java/core/schedules/ScheduleServiceTest.java @@ -23,9 +23,7 @@ import java.time.LocalDate; import java.util.List; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.hibernate.validator.internal.util.Contracts.assertTrue; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @Transactional @@ -75,4 +73,26 @@ public class ScheduleServiceTest { 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); + } } diff --git a/backend/src/test/resources/basicScheduleEntries.sql b/backend/src/test/resources/basicScheduleEntries.sql index 894eab7..5726e26 100644 --- a/backend/src/test/resources/basicScheduleEntries.sql +++ b/backend/src/test/resources/basicScheduleEntries.sql @@ -1,3 +1,3 @@ INSERT INTO abstract_schedule (schedule_type, scheduleid, start_time, stop_time, schedule_date, task, schedule_end, schedule_start) -VALUES (0, 1, null, null, '2023-11-11', 1, null, null), - (0, 2, null, null, '2023-11-11', 2, null, null); \ No newline at end of file +VALUES (0, 1, null, null, '2024-11-11', 1, null, null), + (0, 2, null, null, '2024-11-11', 2, null, null); \ No newline at end of file -- 2.34.1 From 59aaddf789e8afc8f583869ccb0868ca52c28f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 11 Nov 2023 15:51:56 +0100 Subject: [PATCH 06/18] Refactor /schedules/{scheduleID} endpoints (post) --- frontend/src/api/api/schedule.service.ts | 12 ++++++------ .../basic-scheduler/basic-scheduler.component.ts | 2 +- openapi.yaml | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/api/api/schedule.service.ts b/frontend/src/api/api/schedule.service.ts index d686ebc..66a5dc3 100644 --- a/frontend/src/api/api/schedule.service.ts +++ b/frontend/src/api/api/schedule.service.ts @@ -324,12 +324,12 @@ export class ScheduleService { * @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 schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; - public schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; - public schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; - public schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + public schedulesScheduleIDPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public schedulesScheduleIDPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesScheduleIDPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesScheduleIDPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { if (scheduleID === null || scheduleID === undefined) { - throw new Error('Required parameter scheduleID was null or undefined when calling schedulesScheduleIDBasicPost.'); + throw new Error('Required parameter scheduleID was null or undefined when calling schedulesScheduleIDPost.'); } let localVarHeaders = this.defaultHeaders; @@ -373,7 +373,7 @@ export class ScheduleService { responseType_ = 'text'; } - return this.httpClient.post(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}/basic`, + return this.httpClient.post(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}`, basicScheduleFieldInfo, { context: localVarHttpContext, diff --git a/frontend/src/app/schedules/basic-scheduler/basic-scheduler.component.ts b/frontend/src/app/schedules/basic-scheduler/basic-scheduler.component.ts index 791eb1f..cfe4d0d 100644 --- a/frontend/src/app/schedules/basic-scheduler/basic-scheduler.component.ts +++ b/frontend/src/app/schedules/basic-scheduler/basic-scheduler.component.ts @@ -43,7 +43,7 @@ export class BasicSchedulerComponent implements OnChanges{ } }) } else { - this.scheduleService.schedulesScheduleIDBasicPost(this.scheduleEntityInfo!.scheduleID, { + this.scheduleService.schedulesScheduleIDPost(this.scheduleEntityInfo!.scheduleID, { scheduleDate: this.dateCtrl.value }).subscribe({ next: resp => { diff --git a/openapi.yaml b/openapi.yaml index f0e2f4b..f481fad 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1351,7 +1351,7 @@ paths: schema: type: object $ref: "#/components/schemas/SimpleStatusResponse" - /schedules/{scheduleID}/basic: + /schedules/{scheduleID}: post: security: - API_TOKEN: [] @@ -1379,7 +1379,7 @@ paths: application/json: schema: type: object - $ref: '#/components/schemas/SimpleStatusResponse' + $ref: '#/components/schemas/ScheduleInfo' 403: description: No permission content: -- 2.34.1 From d7d8d2060efc711e9d3adab80d9141f0b3be90e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 11 Nov 2023 15:57:46 +0100 Subject: [PATCH 07/18] Refactor /schedules/{scheduleID} endpoints (delete) --- backend/.idea/workspace.xml | 153 ++++++++++-------- .../api/controller/ScheduleController.java | 15 ++ .../core/services/TaskScheduleService.java | 4 + .../core/schedules/ScheduleServiceTest.java | 13 ++ frontend/src/api/api/schedule.service.ts | 122 +++++++------- .../schedule-dashboard.component.ts | 2 +- openapi.yaml | 11 -- 7 files changed, 181 insertions(+), 139 deletions(-) diff --git a/backend/.idea/workspace.xml b/backend/.idea/workspace.xml index fc7a90a..cf60247 100644 --- a/backend/.idea/workspace.xml +++ b/backend/.idea/workspace.xml @@ -4,9 +4,11 @@