From e463cca9b25b500bd9a7c43284b6e79f1484c019 Mon Sep 17 00:00:00 2001 From: Jan Tymel <410388@mail.muni.cz> Date: Sat, 6 Feb 2021 10:26:06 +0100 Subject: [PATCH] Add API for changing tasks' order Resolves #2 --- .../demo/controller/TasksController.java | 22 +++++++++++++++++-- .../demo/repository/TaskRepository.java | 20 +++++++++++++++++ .../com/example/demo/service/TaskService.java | 22 +++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/demo/controller/TasksController.java b/src/main/java/com/example/demo/controller/TasksController.java index eb252c4c..dd556456 100644 --- a/src/main/java/com/example/demo/controller/TasksController.java +++ b/src/main/java/com/example/demo/controller/TasksController.java @@ -30,11 +30,10 @@ import javax.validation.Valid; @RequestMapping(value = "/training-definitions/{definitionId}/phases/{phaseId}/tasks", produces = MediaType.APPLICATION_JSON_VALUE) @CrossOrigin(origins = "*", allowCredentials = "true", allowedHeaders = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PUT}) -@Api(value = "/training-definitions/{definitionId}/phases", +@Api(value = "/training-definitions/{definitionId}/tasks", tags = "Tasks", consumes = MediaType.APPLICATION_JSON_VALUE, authorizations = @Authorization(value = "bearerAuth")) - public class TasksController { @Autowired @@ -161,4 +160,23 @@ public class TasksController { return ResponseEntity.ok().build(); } + + @ApiOperation(httpMethod = "PUT", + value = "Move task to specified order", + nickname = "moveTaskToSpecifiedOrder", + produces = MediaType.APPLICATION_JSON_VALUE + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Task moved to specified order"), + @ApiResponse(code = 500, message = "Unexpected application error") + }) + @PutMapping(value = "/{taskIdFrom}/move-to/{newPosition}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<Void> moveTaskToSpecifiedOrder( + @ApiParam(value = "Task ID - from", required = true) @PathVariable(name = "taskIdFrom") Long taskIdFrom, + @ApiParam(value = "Position (order) to which the task should be moved", required = true) @PathVariable(name = "newPosition") int newPosition) { + + taskService.moveTaskToSpecifiedOrder(taskIdFrom, newPosition); + + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/com/example/demo/repository/TaskRepository.java b/src/main/java/com/example/demo/repository/TaskRepository.java index 91642c88..584402d4 100644 --- a/src/main/java/com/example/demo/repository/TaskRepository.java +++ b/src/main/java/com/example/demo/repository/TaskRepository.java @@ -12,6 +12,26 @@ public interface TaskRepository extends JpaRepository<Task, Long> { @Query("SELECT COALESCE(MAX(g.order), -1) FROM Task g WHERE g.trainingPhase.id = :phaseId") Integer getCurrentMaxOrder(@Param("phaseId") Long phaseId); + @Modifying + @Query("UPDATE Task t SET t.order = t.order - 1 " + + "WHERE t.trainingPhase.id = :trainingPhaseId " + + "AND t.order > :lowerBound " + + "AND t.order <= :upperBound ") + void decreaseOrderOfTasksOnInterval(@Param("trainingPhaseId") Long trainingPhaseId, + @Param("lowerBound") int lowerBound, + @Param("upperBound") int upperBound); + + + @Modifying + @Query("UPDATE Task t SET t.order = t.order + 1 " + + "WHERE t.trainingPhase.id = :trainingPhaseId " + + "AND t.order >= :lowerBound " + + "AND t.order < :upperBound ") + void increaseOrderOfTasksOnInterval(@Param("trainingPhaseId") Long trainingPhaseId, + @Param("lowerBound") int lowerBound, + @Param("upperBound") int upperBound); + + @Transactional @Modifying @Query("UPDATE Task t SET t.order = t.order - 1 " + diff --git a/src/main/java/com/example/demo/service/TaskService.java b/src/main/java/com/example/demo/service/TaskService.java index a4092e65..2d87bcb8 100644 --- a/src/main/java/com/example/demo/service/TaskService.java +++ b/src/main/java/com/example/demo/service/TaskService.java @@ -14,6 +14,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; @@ -133,4 +134,25 @@ public class TaskService { taskRepository.delete(task); } + + @Transactional + public void moveTaskToSpecifiedOrder(Long taskIdFrom, int newPosition) { + Task task = taskRepository.findById(taskIdFrom) + .orElseThrow(() -> new RuntimeException("Task was not found")); + // TODO throw proper exception once kypo2-training is migrated + + int fromOrder = task.getOrder(); + + if (fromOrder < newPosition) { + taskRepository.decreaseOrderOfTasksOnInterval(task.getTrainingPhase().getId(), fromOrder, newPosition); + } else if (fromOrder > newPosition) { + taskRepository.increaseOrderOfTasksOnInterval(task.getTrainingPhase().getId(), newPosition, fromOrder); + } else { + // nothing should be changed, no further actions needed + return; + } + + task.setOrder(newPosition); + taskRepository.save(task); + } } -- GitLab