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(); + } }