schedule-refactor #45

Merged
sebastian merged 18 commits from schedule-refactor into master 2023-11-11 18:56:16 +01:00
11 changed files with 232 additions and 6 deletions
Showing only changes of commit dcc488fced - Show all commits

View File

@ -1,13 +1,20 @@
package core.api.controller; 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.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.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List; import java.util.List;
@ -17,11 +24,46 @@ import java.util.List;
public class ScheduleController { public class ScheduleController {
@Autowired private TaskScheduleService taskScheduleService; @Autowired private TaskScheduleService taskScheduleService;
@Autowired private TaskService taskService;
@GetMapping("/schedules") @GetMapping("/schedules")
public ResponseEntity<?> loadAllSchedulesOfUser() { public ResponseEntity<?> loadAllSchedulesOfUser() {
String username = SecurityContextHolder.getContext().getAuthentication().getName(); String username = SecurityContextHolder.getContext().getAuthentication().getName();
List<AbstractSchedule> schedules = taskScheduleService.getAllSchedulesOfUser(username); List<AbstractSchedule> 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<Task> 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<AbstractSchedule> 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<Task> 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<AbstractSchedule> scheduleResult = taskScheduleService.scheduleBasic(permissionResult.getResult(), (BasicScheduleFieldInfo) scheduleFieldInfo);
return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo());
} else {
return ResponseEntity.status(400).body(new SimpleStatusResponse("failed"));
}
} }
} }

View File

@ -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;
}
}

View File

@ -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<TaskgroupEntityInfo> taskgroupPath) {
super(scheduleID, scheduleType, startTime, stopTime, activeMinutes, task, taskgroupPath);
}
}

View File

@ -0,0 +1,4 @@
package core.api.models.timemanager.taskSchedule;
public abstract class ScheduleFieldInfo {
}

View File

@ -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<TaskgroupEntityInfo> taskgroupPath;
public ScheduleInfo(long scheduleID, ScheduleType scheduleType, LocalDateTime startTime, LocalDateTime stopTime, int activeMinutes, Task task, List<TaskgroupEntityInfo> taskgroupPath) {
this.scheduleID = scheduleID;
this.scheduleType = scheduleType;
this.startTime = startTime;
this.stopTime = stopTime;
this.activeMinutes = activeMinutes;
this.task = new TaskShortInfo(task);
this.taskgroupPath = taskgroupPath;
}
}

View File

@ -0,0 +1,8 @@
package core.api.models.timemanager.taskSchedule;
public enum ScheduleType {
BASIC,
MODERATE,
ADVANCED;
}

View File

@ -1,5 +1,7 @@
package core.entities.timemanager; package core.entities.timemanager;
import core.api.models.timemanager.taskSchedule.ScheduleInfo;
import javax.persistence.*; import javax.persistence.*;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Objects; import java.util.Objects;
@ -12,14 +14,14 @@ public abstract class AbstractSchedule {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private long scheduleID; protected long scheduleID;
@ManyToOne @ManyToOne
@JoinColumn(referencedColumnName = "taskID", name = "task") @JoinColumn(referencedColumnName = "taskID", name = "task")
private Task task; protected Task task;
private LocalDateTime startTime; protected LocalDateTime startTime;
private LocalDateTime stopTime; protected LocalDateTime stopTime;
public AbstractSchedule() { public AbstractSchedule() {
} }
@ -30,6 +32,10 @@ public abstract class AbstractSchedule {
this.stopTime = stopTime; this.stopTime = stopTime;
} }
public AbstractSchedule(Task task) {
this.task = task;
}
public long getScheduleID() { public long getScheduleID() {
return scheduleID; return scheduleID;
} }
@ -74,4 +80,6 @@ public abstract class AbstractSchedule {
public int hashCode() { public int hashCode() {
return Objects.hash(scheduleID, task, startTime, stopTime); return Objects.hash(scheduleID, task, startTime, stopTime);
} }
public abstract ScheduleInfo toScheduleInfo();
} }

View File

@ -1,5 +1,7 @@
package core.entities.timemanager; package core.entities.timemanager;
import core.api.models.timemanager.taskSchedule.ScheduleInfo;
import javax.persistence.DiscriminatorValue; import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity; import javax.persistence.Entity;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -9,4 +11,9 @@ public class AdvancedTaskSchedule extends AbstractSchedule {
private LocalDateTime scheduleStart; private LocalDateTime scheduleStart;
private LocalDateTime scheduleEnd; private LocalDateTime scheduleEnd;
@Override
public ScheduleInfo toScheduleInfo() {
return null;
}
} }

View File

@ -1,8 +1,16 @@
package core.entities.timemanager; 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 javax.persistence.*;
import java.time.Duration;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects; import java.util.Objects;
@Entity @Entity
@ -19,6 +27,11 @@ public class BasicTaskSchedule extends AbstractSchedule{
this.scheduleDate = scheduleDate; this.scheduleDate = scheduleDate;
} }
public BasicTaskSchedule(Task task, LocalDate scheduleDate) {
super(task);
this.scheduleDate = scheduleDate;
}
public LocalDate getScheduleDate() { public LocalDate getScheduleDate() {
return scheduleDate; return scheduleDate;
} }
@ -26,4 +39,22 @@ public class BasicTaskSchedule extends AbstractSchedule{
public void setScheduleDate(LocalDate scheduleDate) { public void setScheduleDate(LocalDate scheduleDate) {
this.scheduleDate = scheduleDate; this.scheduleDate = scheduleDate;
} }
public ScheduleInfo toScheduleInfo() {
int activeMinutes = calcActiveMinutes();
List<TaskgroupEntityInfo> 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();
}
}
} }

View File

@ -1,12 +1,17 @@
package core.services; package core.services;
import core.api.models.timemanager.taskSchedule.BasicScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.ScheduleFieldInfo;
import core.entities.User; import core.entities.User;
import core.entities.timemanager.AbstractSchedule; import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task;
import core.repositories.UserRepository; import core.repositories.UserRepository;
import core.repositories.timemanager.ScheduleRepository; import core.repositories.timemanager.ScheduleRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -19,4 +24,15 @@ public class TaskScheduleService {
public List<AbstractSchedule> getAllSchedulesOfUser(String username) { public List<AbstractSchedule> getAllSchedulesOfUser(String username) {
return scheduleRepository.findAllByUsername(username); return scheduleRepository.findAllByUsername(username);
} }
public ServiceResult<AbstractSchedule> 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);
}
} }

View File

@ -1,7 +1,13 @@
package core.schedules; 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.AbstractSchedule;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task;
import core.repositories.timemanager.TaskgroupRepository; import core.repositories.timemanager.TaskgroupRepository;
import core.services.ServiceExitCode;
import core.services.ServiceResult;
import core.services.TaskScheduleService; import core.services.TaskScheduleService;
import core.services.TaskgroupService; import core.services.TaskgroupService;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -13,8 +19,10 @@ import org.springframework.test.context.jdbc.SqlGroup;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import java.time.LocalDate;
import java.util.List; import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.hibernate.validator.internal.util.Contracts.assertTrue; import static org.hibernate.validator.internal.util.Contracts.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue; 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, 1L)));
assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 2L))); 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<AbstractSchedule> 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<AbstractSchedule> 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<AbstractSchedule> 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();
}
} }