From 50ee66cae6d2d73b3a09c196d8dba3bcea0478d2 Mon Sep 17 00:00:00 2001
From: Jan Tymel <410388@mail.muni.cz>
Date: Wed, 27 Jan 2021 06:52:20 +0100
Subject: [PATCH] Change REST API creating a new task according to the new
 design, add task clone API

Related to #10
---
 ...tiveTrainingDefinitionsRestController.java | 32 ++++----
 .../demo/controller/PhasesController.java     |  4 +-
 .../demo/controller/TasksController.java      | 80 +++++++++++++++++++
 .../demo/service/LevelOperationsService.java  | 17 ++--
 .../com/example/demo/service/TaskService.java | 41 +++++++---
 5 files changed, 137 insertions(+), 37 deletions(-)
 create mode 100644 src/main/java/com/example/demo/controller/TasksController.java

diff --git a/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java b/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java
index 3152df7b..b1e018bf 100644
--- a/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java
+++ b/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java
@@ -164,22 +164,22 @@ public class AdaptiveTrainingDefinitionsRestController {
         levelOperationsService.updateTask(taskUpdateDto);
     }
 
-    @ApiOperation(httpMethod = "POST",
-            value = "Create a new task",
-            response = BaseLevelDto.class,
-            nickname = "createTask",
-            produces = MediaType.APPLICATION_JSON_VALUE
-    )
-    @ApiResponses(value = {
-            @ApiResponse(code = 200, message = "Task created"),
-            @ApiResponse(code = 500, message = "Unexpected application error")
-    })
-    @PostMapping(path = "/phases/{phaseId}")
-    public BaseLevelDto createTask(
-            @ApiParam(value = "Phase ID", required = true) @PathVariable(name = "phaseId") Long phaseId) {
-
-        return levelOperationsService.createTask(phaseId);
-    }
+//    @ApiOperation(httpMethod = "POST",
+//            value = "Create a new task",
+//            response = BaseLevelDto.class,
+//            nickname = "createTask",
+//            produces = MediaType.APPLICATION_JSON_VALUE
+//    )
+//    @ApiResponses(value = {
+//            @ApiResponse(code = 200, message = "Task created"),
+//            @ApiResponse(code = 500, message = "Unexpected application error")
+//    })
+//    @PostMapping(path = "/phases/{phaseId}")
+//    public BaseLevelDto createTask(
+//            @ApiParam(value = "Phase ID", required = true) @PathVariable(name = "phaseId") Long phaseId) {
+//
+//        return levelOperationsService.createTask(phaseId);
+//    }
 
     @ApiOperation(httpMethod = "POST",
             value = "Create a new question in questionnaire",
diff --git a/src/main/java/com/example/demo/controller/PhasesController.java b/src/main/java/com/example/demo/controller/PhasesController.java
index d95cf6f3..03904972 100644
--- a/src/main/java/com/example/demo/controller/PhasesController.java
+++ b/src/main/java/com/example/demo/controller/PhasesController.java
@@ -13,12 +13,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.CrossOrigin;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
@@ -38,7 +36,7 @@ public class PhasesController {
             value = "Create a new phase",
             notes = "Creates a new default phase with a specified type",
             response = BaseLevelDto.class,
-            nickname = "createLevel",
+            nickname = "createPhase",
             produces = MediaType.APPLICATION_JSON_VALUE
     )
     @ApiResponses(value = {
diff --git a/src/main/java/com/example/demo/controller/TasksController.java b/src/main/java/com/example/demo/controller/TasksController.java
new file mode 100644
index 00000000..bd2bf827
--- /dev/null
+++ b/src/main/java/com/example/demo/controller/TasksController.java
@@ -0,0 +1,80 @@
+package com.example.demo.controller;
+
+import com.example.demo.dto.TaskDto;
+import com.example.demo.service.TaskService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(value = "/training-definitions/{definitionId}/phases/{phaseId}/tasks", produces = MediaType.APPLICATION_JSON_VALUE)
+@Api(value = "/training-definitions/{definitionId}/phases",
+        tags = "Tasks",
+        consumes = MediaType.APPLICATION_JSON_VALUE,
+        authorizations = @Authorization(value = "bearerAuth"))
+
+public class TasksController {
+
+    @Autowired
+    private TaskService taskService;
+
+    @ApiOperation(httpMethod = "POST",
+            value = "Create a new task in a phase",
+            notes = "Creates a new default task in a specified game phase",
+            response = TaskDto.class,
+            nickname = "createTask",
+            produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    @ApiResponses(value = {
+            @ApiResponse(code = 201, message = "Task created"),
+            @ApiResponse(code = 500, message = "Unexpected application error")
+    })
+    @PostMapping
+    public ResponseEntity<TaskDto> createTask(
+            @ApiParam(value = "Training definition ID", required = true)
+            @PathVariable(name = "definitionId") Long definitionId,
+            @ApiParam(value = "Game phase ID", required = true)
+            @PathVariable(name = "phaseId") Long phaseId) {
+
+        TaskDto createdTask = taskService.createDefaultTask(definitionId, phaseId);
+
+        return new ResponseEntity<>(createdTask, HttpStatus.CREATED);
+    }
+
+    @ApiOperation(httpMethod = "POST",
+            value = "Clone task inside of the game phase",
+            notes = "Creates a new task with the same properties as the specified task (pattern)",
+            response = TaskDto.class,
+            nickname = "cloneTask",
+            produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    @ApiResponses(value = {
+            @ApiResponse(code = 201, message = "Task cloned"),
+            @ApiResponse(code = 500, message = "Unexpected application error")
+    })
+    @PostMapping(path = "/{taskId}")
+    public ResponseEntity<TaskDto> cloneTask(
+            @ApiParam(value = "Training definition ID", required = true)
+            @PathVariable(name = "definitionId") Long definitionId,
+            @ApiParam(value = "Game phase ID", required = true)
+            @PathVariable(name = "phaseId") Long phaseId,
+            @ApiParam(value = "Task ID", required = true)
+            @PathVariable(name = "taskId") Long taskId) {
+
+        TaskDto createdTask = taskService.cloneTask(definitionId, phaseId, taskId);
+
+        return new ResponseEntity<>(createdTask, HttpStatus.CREATED);
+    }
+
+}
diff --git a/src/main/java/com/example/demo/service/LevelOperationsService.java b/src/main/java/com/example/demo/service/LevelOperationsService.java
index 7837e8d0..7309f3e3 100644
--- a/src/main/java/com/example/demo/service/LevelOperationsService.java
+++ b/src/main/java/com/example/demo/service/LevelOperationsService.java
@@ -1,13 +1,14 @@
 package com.example.demo.service;
 
 import com.example.demo.domain.BaseLevel;
+import com.example.demo.domain.InfoLevel;
 import com.example.demo.domain.PhaseLevel;
 import com.example.demo.domain.Question;
 import com.example.demo.domain.QuestionChoice;
 import com.example.demo.domain.QuestionnaireLevel;
 import com.example.demo.domain.Task;
-import com.example.demo.domain.InfoLevel;
 import com.example.demo.dto.BaseLevelDto;
+import com.example.demo.dto.InfoLevelUpdateDto;
 import com.example.demo.dto.PhaseCreateDTO;
 import com.example.demo.dto.PhaseLevelUpdateDto;
 import com.example.demo.dto.QuestionChoiceDto;
@@ -15,9 +16,7 @@ import com.example.demo.dto.QuestionChoiceUpdateDto;
 import com.example.demo.dto.QuestionDto;
 import com.example.demo.dto.QuestionUpdateDto;
 import com.example.demo.dto.QuestionnaireUpdateDto;
-import com.example.demo.dto.TaskDto;
 import com.example.demo.dto.TaskUpdateDto;
-import com.example.demo.dto.InfoLevelUpdateDto;
 import com.example.demo.enums.PhaseType;
 import com.example.demo.enums.QuestionType;
 import com.example.demo.mapper.BeanMapper;
@@ -122,12 +121,12 @@ public class LevelOperationsService {
         return baseLevelDto;
     }
 
-    public BaseLevelDto createTask(Long phaseId) {
-        TaskDto createdTask = taskService.createDefaultTask(phaseId);
-        createdTask.setPhaseType(PhaseType.task);
-
-        return createdTask;
-    }
+//    public BaseLevelDto createTask(Long phaseId) {
+//        TaskDto createdTask = taskService.createDefaultTask(phaseId);
+//        createdTask.setPhaseType(PhaseType.task);
+//
+//        return createdTask;
+//    }
 
     public BaseLevelDto getLevel(Long levelId) {
         Optional<BaseLevel> level = baseLevelRepository.findById(levelId);
diff --git a/src/main/java/com/example/demo/service/TaskService.java b/src/main/java/com/example/demo/service/TaskService.java
index e083f535..51b87b64 100644
--- a/src/main/java/com/example/demo/service/TaskService.java
+++ b/src/main/java/com/example/demo/service/TaskService.java
@@ -1,15 +1,16 @@
 package com.example.demo.service;
 
-import com.example.demo.domain.Task;
 import com.example.demo.domain.PhaseLevel;
+import com.example.demo.domain.Task;
 import com.example.demo.dto.TaskCreateDto;
 import com.example.demo.dto.TaskDto;
 import com.example.demo.mapper.BeanMapper;
-import com.example.demo.repository.TaskRepository;
 import com.example.demo.repository.PhaseLevelRepository;
+import com.example.demo.repository.TaskRepository;
 import org.apache.commons.collections4.IterableUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -31,16 +32,38 @@ public class TaskService {
         this.phaseLevelRepository = phaseLevelRepository;
     }
 
-    public TaskDto createDefaultTask(Long phaseId) {
-        Optional<PhaseLevel> phaseLevel = phaseLevelRepository.findById(phaseId);
-        if (phaseLevel.isEmpty()) {
-            // TODO return 404
-            return null;
-        }
+    public TaskDto createDefaultTask(Long trainingDefinitionId, Long phaseId) {
+        PhaseLevel gamePhase = phaseLevelRepository.findById(phaseId)
+                .orElseThrow(() -> new RuntimeException("Game phase was not found"));
+        // TODO throw proper exception once kypo2-training is migrated
+
+        // TODO add check to trainingDefinitionId (field structure will be probably changed)
 
         Task task = new Task();
         task.setTitle("Title of task");
-        task.setPhaseLevel(phaseLevel.get());
+        task.setPhaseLevel(gamePhase);
+        task.setOrder(taskRepository.getCurrentMaxOrder(phaseId) + 1);
+
+        Task persistedEntity = taskRepository.save(task);
+
+        return BeanMapper.INSTANCE.toDto(persistedEntity);
+    }
+
+    public TaskDto cloneTask(Long trainingDefinitionId, Long phaseId, Long taskId) {
+        Task taskToBeCloned = taskRepository.findById(taskId)
+                .orElseThrow(() -> new RuntimeException("Task was not found"));
+        // TODO throw proper exception once kypo2-training is migrated
+
+        PhaseLevel gamePhase = phaseLevelRepository.findById(phaseId)
+                .orElseThrow(() -> new RuntimeException("Game phase was not found"));
+
+        // TODO add check to trainingDefinitionId (field structure will be probably changed)
+
+        Task task = new Task();
+        BeanUtils.copyProperties(taskToBeCloned, task);
+
+        task.setId(null);
+        task.setPhaseLevel(gamePhase);
         task.setOrder(taskRepository.getCurrentMaxOrder(phaseId) + 1);
 
         Task persistedEntity = taskRepository.save(task);
-- 
GitLab