From 1bc3dd601e02585055b6070cab878fe237ea965e Mon Sep 17 00:00:00 2001
From: Jan Tymel <410388@mail.muni.cz>
Date: Mon, 18 Jan 2021 07:13:42 +0100
Subject: [PATCH] Add questionnaires + implement POST methods, choices are not
 working yet though

---
 README.md                                     |   2 +
 ...tiveTrainingDefinitionsRestController.java |  40 ++++++-
 .../com/example/demo/domain/Question.java     | 111 ++++++++++++++++++
 .../example/demo/domain/QuestionChoice.java   |  65 ++++++++++
 .../demo/domain/QuestionnaireLevel.java       |  24 ++++
 .../com/example/demo/dto/BaseLevelDto.java    |   2 +-
 .../example/demo/dto/QuestionChoiceDto.java   |  43 +++++++
 .../com/example/demo/dto/QuestionDto.java     |  84 +++++++++++++
 .../demo/dto/QuestionnaireLevelDto.java       |  16 +++
 .../dto/input/GameDefinitionCreateDto.java    |   1 +
 .../com/example/demo/dto/input/LevelType.java |   8 --
 .../com/example/demo/enums/LevelType.java     |   9 ++
 .../com/example/demo/enums/QuestionType.java  |   4 +
 .../com/example/demo/mapper/BeanMapper.java   |  31 ++++-
 .../repository/QuestionChoiceRepository.java  |  12 ++
 .../demo/repository/QuestionRepository.java   |  12 ++
 .../QuestionnaireLevelRepository.java         |   9 ++
 .../demo/service/LevelOperationsService.java  |  28 ++++-
 .../demo/service/QuestionChoiceService.java   |  41 +++++++
 .../example/demo/service/QuestionService.java |  42 +++++++
 .../service/QuestionnaireLevelService.java    |  32 +++++
 21 files changed, 599 insertions(+), 17 deletions(-)
 create mode 100644 src/main/java/com/example/demo/domain/Question.java
 create mode 100644 src/main/java/com/example/demo/domain/QuestionChoice.java
 create mode 100644 src/main/java/com/example/demo/domain/QuestionnaireLevel.java
 create mode 100644 src/main/java/com/example/demo/dto/QuestionChoiceDto.java
 create mode 100644 src/main/java/com/example/demo/dto/QuestionDto.java
 create mode 100644 src/main/java/com/example/demo/dto/QuestionnaireLevelDto.java
 delete mode 100644 src/main/java/com/example/demo/dto/input/LevelType.java
 create mode 100644 src/main/java/com/example/demo/enums/LevelType.java
 create mode 100644 src/main/java/com/example/demo/enums/QuestionType.java
 create mode 100644 src/main/java/com/example/demo/repository/QuestionChoiceRepository.java
 create mode 100644 src/main/java/com/example/demo/repository/QuestionRepository.java
 create mode 100644 src/main/java/com/example/demo/repository/QuestionnaireLevelRepository.java
 create mode 100644 src/main/java/com/example/demo/service/QuestionChoiceService.java
 create mode 100644 src/main/java/com/example/demo/service/QuestionService.java
 create mode 100644 src/main/java/com/example/demo/service/QuestionnaireLevelService.java

diff --git a/README.md b/README.md
index d1c63369..5821e812 100644
--- a/README.md
+++ b/README.md
@@ -7,4 +7,6 @@
 * Deleting level should work
   * Including decreasing of order attribute
     * except for tasks, there is still a problem with setting the order attribute
+* Questionnaires added
+  * Currently only POST methods implemented. However, creating a new question choice is not working yet
 
diff --git a/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java b/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java
index 80c084dc..405c1e84 100644
--- a/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java
+++ b/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java
@@ -1,9 +1,11 @@
 package com.example.demo.controller;
 
 import com.example.demo.dto.BaseLevelDto;
+import com.example.demo.dto.QuestionChoiceDto;
+import com.example.demo.dto.QuestionDto;
 import com.example.demo.dto.TaskUpdateDto;
 import com.example.demo.dto.InfoLevelUpdateDto;
-import com.example.demo.dto.input.LevelType;
+import com.example.demo.enums.LevelType;
 import com.example.demo.service.LevelOperationsService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -88,7 +90,7 @@ public class AdaptiveTrainingDefinitionsRestController {
     @PostMapping(path = "/levels/{levelType}")
     public BaseLevelDto createLevel(
             @ApiParam(value = "Training definition ID", required = true) @RequestParam(name = "definitionId") Long definitionId,
-            @ApiParam(value = "Level type", allowableValues = "task, assessment, info, phase", required = true)
+            @ApiParam(value = "Level type", allowableValues = "questionnaire, assessment, info, phase", required = true)
             @PathVariable("levelType") LevelType levelType) {
 
         return levelOperationsService.createLevel(definitionId, levelType);
@@ -159,4 +161,38 @@ public class AdaptiveTrainingDefinitionsRestController {
 
         return levelOperationsService.createTask(phaseId);
     }
+
+    @ApiOperation(httpMethod = "POST",
+            value = "Create a new question in questionnaire",
+            response = BaseLevelDto.class,
+            nickname = "createQuestion",
+            produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    @ApiResponses(value = {
+            @ApiResponse(code = 200, message = "Question created"),
+            @ApiResponse(code = 500, message = "Unexpected application error")
+    })
+    @PostMapping(path = "/questionnaires/{questionnaireId}")
+    public QuestionDto createQuestion(
+            @ApiParam(value = "Questionnaire ID", required = true) @PathVariable(name = "questionnaireId") Long questionnaireId) {
+
+        return levelOperationsService.createQuestion(questionnaireId);
+    }
+
+    @ApiOperation(httpMethod = "POST",
+            value = "Create a new choice in question",
+            response = BaseLevelDto.class,
+            nickname = "createQuestionChoice",
+            produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    @ApiResponses(value = {
+            @ApiResponse(code = 200, message = "Question choice created"),
+            @ApiResponse(code = 500, message = "Unexpected application error")
+    })
+    @PostMapping(path = "/questions/{questionId}")
+    public QuestionChoiceDto createQuestionChoice(
+            @ApiParam(value = "Question ID", required = true) @PathVariable(name = "questionId") Long questionId) {
+
+        return levelOperationsService.createQuestionChoice(questionId);
+    }
 }
diff --git a/src/main/java/com/example/demo/domain/Question.java b/src/main/java/com/example/demo/domain/Question.java
new file mode 100644
index 00000000..31cc7972
--- /dev/null
+++ b/src/main/java/com/example/demo/domain/Question.java
@@ -0,0 +1,111 @@
+package com.example.demo.domain;
+
+import com.example.demo.enums.QuestionType;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OrderBy;
+import java.util.ArrayList;
+import java.util.List;
+
+@Entity
+public class Question {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private QuestionType questionType;
+    private String text;
+    private Integer points;
+    private Integer penalty;
+    private boolean required;
+
+    @Column(name = "order_in_questionnaire", nullable = false)
+    private Integer order;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    private QuestionnaireLevel questionnaireLevel;
+
+    @OrderBy
+    @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
+    private List<QuestionChoice> choices = new ArrayList<>();
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public QuestionType getQuestionType() {
+        return questionType;
+    }
+
+    public void setQuestionType(QuestionType questionType) {
+        this.questionType = questionType;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public Integer getPoints() {
+        return points;
+    }
+
+    public void setPoints(Integer points) {
+        this.points = points;
+    }
+
+    public Integer getPenalty() {
+        return penalty;
+    }
+
+    public void setPenalty(Integer penalty) {
+        this.penalty = penalty;
+    }
+
+    public boolean isRequired() {
+        return required;
+    }
+
+    public void setRequired(boolean required) {
+        this.required = required;
+    }
+
+    public Integer getOrder() {
+        return order;
+    }
+
+    public void setOrder(Integer order) {
+        this.order = order;
+    }
+
+    public QuestionnaireLevel getQuestionnaireLevel() {
+        return questionnaireLevel;
+    }
+
+    public void setQuestionnaireLevel(QuestionnaireLevel questionnaireLevel) {
+        this.questionnaireLevel = questionnaireLevel;
+    }
+
+    public List<QuestionChoice> getChoices() {
+        return choices;
+    }
+
+    public void setChoices(List<QuestionChoice> choices) {
+        this.choices = choices;
+    }
+}
diff --git a/src/main/java/com/example/demo/domain/QuestionChoice.java b/src/main/java/com/example/demo/domain/QuestionChoice.java
new file mode 100644
index 00000000..b1bafaa5
--- /dev/null
+++ b/src/main/java/com/example/demo/domain/QuestionChoice.java
@@ -0,0 +1,65 @@
+package com.example.demo.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+
+@Entity
+public class QuestionChoice {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private String text;
+    private boolean correct;
+
+    @Column(name = "order_in_question", nullable = false)
+    private Integer order;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    private Question question;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public boolean isCorrect() {
+        return correct;
+    }
+
+    public void setCorrect(boolean correct) {
+        this.correct = correct;
+    }
+
+    public Integer getOrder() {
+        return order;
+    }
+
+    public void setOrder(Integer order) {
+        this.order = order;
+    }
+
+    public Question getQuestion() {
+        return question;
+    }
+
+    public void setQuestion(Question question) {
+        this.question = question;
+    }
+}
diff --git a/src/main/java/com/example/demo/domain/QuestionnaireLevel.java b/src/main/java/com/example/demo/domain/QuestionnaireLevel.java
new file mode 100644
index 00000000..9049f76f
--- /dev/null
+++ b/src/main/java/com/example/demo/domain/QuestionnaireLevel.java
@@ -0,0 +1,24 @@
+package com.example.demo.domain;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.OneToMany;
+import javax.persistence.OrderBy;
+import java.util.List;
+
+@Entity
+public class QuestionnaireLevel extends BaseLevel {
+
+    @OrderBy
+    @OneToMany(mappedBy = "questionnaireLevel", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
+    private List<Question> questions;
+
+    public List<Question> getQuestions() {
+        return questions;
+    }
+
+    public void setQuestions(List<Question> questions) {
+        this.questions = questions;
+    }
+}
diff --git a/src/main/java/com/example/demo/dto/BaseLevelDto.java b/src/main/java/com/example/demo/dto/BaseLevelDto.java
index 2094ccef..f6c3262e 100644
--- a/src/main/java/com/example/demo/dto/BaseLevelDto.java
+++ b/src/main/java/com/example/demo/dto/BaseLevelDto.java
@@ -1,6 +1,6 @@
 package com.example.demo.dto;
 
-import com.example.demo.dto.input.LevelType;
+import com.example.demo.enums.LevelType;
 
 import java.io.Serializable;
 
diff --git a/src/main/java/com/example/demo/dto/QuestionChoiceDto.java b/src/main/java/com/example/demo/dto/QuestionChoiceDto.java
new file mode 100644
index 00000000..6259a57e
--- /dev/null
+++ b/src/main/java/com/example/demo/dto/QuestionChoiceDto.java
@@ -0,0 +1,43 @@
+package com.example.demo.dto;
+
+import java.io.Serializable;
+
+public class QuestionChoiceDto implements Serializable {
+
+    private Long id;
+    private String text;
+    private boolean correct;
+    private Integer order;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public boolean isCorrect() {
+        return correct;
+    }
+
+    public void setCorrect(boolean correct) {
+        this.correct = correct;
+    }
+
+    public Integer getOrder() {
+        return order;
+    }
+
+    public void setOrder(Integer order) {
+        this.order = order;
+    }
+}
diff --git a/src/main/java/com/example/demo/dto/QuestionDto.java b/src/main/java/com/example/demo/dto/QuestionDto.java
new file mode 100644
index 00000000..03044ee1
--- /dev/null
+++ b/src/main/java/com/example/demo/dto/QuestionDto.java
@@ -0,0 +1,84 @@
+package com.example.demo.dto;
+
+import com.example.demo.domain.QuestionnaireLevel;
+import com.example.demo.enums.QuestionType;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class QuestionDto implements Serializable {
+
+    private Long id;
+
+    private QuestionType questionType;
+    private String text;
+    private Integer points;
+    private Integer penalty;
+    private boolean required;
+    private Integer order;
+    private List<QuestionChoiceDto> choices;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public QuestionType getQuestionType() {
+        return questionType;
+    }
+
+    public void setQuestionType(QuestionType questionType) {
+        this.questionType = questionType;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public Integer getPoints() {
+        return points;
+    }
+
+    public void setPoints(Integer points) {
+        this.points = points;
+    }
+
+    public Integer getPenalty() {
+        return penalty;
+    }
+
+    public void setPenalty(Integer penalty) {
+        this.penalty = penalty;
+    }
+
+    public boolean isRequired() {
+        return required;
+    }
+
+    public void setRequired(boolean required) {
+        this.required = required;
+    }
+
+    public Integer getOrder() {
+        return order;
+    }
+
+    public void setOrder(Integer order) {
+        this.order = order;
+    }
+
+    public List<QuestionChoiceDto> getChoices() {
+        return choices;
+    }
+
+    public void setChoices(List<QuestionChoiceDto> choices) {
+        this.choices = choices;
+    }
+}
diff --git a/src/main/java/com/example/demo/dto/QuestionnaireLevelDto.java b/src/main/java/com/example/demo/dto/QuestionnaireLevelDto.java
new file mode 100644
index 00000000..bec77996
--- /dev/null
+++ b/src/main/java/com/example/demo/dto/QuestionnaireLevelDto.java
@@ -0,0 +1,16 @@
+package com.example.demo.dto;
+
+import java.util.List;
+
+public class QuestionnaireLevelDto extends BaseLevelDto {
+
+    private List<QuestionDto> questions;
+
+    public List<QuestionDto> getQuestions() {
+        return questions;
+    }
+
+    public void setQuestions(List<QuestionDto> questions) {
+        this.questions = questions;
+    }
+}
diff --git a/src/main/java/com/example/demo/dto/input/GameDefinitionCreateDto.java b/src/main/java/com/example/demo/dto/input/GameDefinitionCreateDto.java
index 214536ad..4a230bc1 100644
--- a/src/main/java/com/example/demo/dto/input/GameDefinitionCreateDto.java
+++ b/src/main/java/com/example/demo/dto/input/GameDefinitionCreateDto.java
@@ -1,6 +1,7 @@
 package com.example.demo.dto.input;
 
 import com.example.demo.dto.AttachmentDto;
+import com.example.demo.enums.LevelType;
 
 import java.util.List;
 
diff --git a/src/main/java/com/example/demo/dto/input/LevelType.java b/src/main/java/com/example/demo/dto/input/LevelType.java
deleted file mode 100644
index 94326905..00000000
--- a/src/main/java/com/example/demo/dto/input/LevelType.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.example.demo.dto.input;
-
-public enum LevelType {
-    assessment,
-    task,
-    info,
-    phase
-}
diff --git a/src/main/java/com/example/demo/enums/LevelType.java b/src/main/java/com/example/demo/enums/LevelType.java
new file mode 100644
index 00000000..da1504d1
--- /dev/null
+++ b/src/main/java/com/example/demo/enums/LevelType.java
@@ -0,0 +1,9 @@
+package com.example.demo.enums;
+
+public enum LevelType {
+    assessment, // TODO deprecated, should be replaced by questionnaire
+    questionnaire,
+    task,
+    info,
+    phase
+}
diff --git a/src/main/java/com/example/demo/enums/QuestionType.java b/src/main/java/com/example/demo/enums/QuestionType.java
new file mode 100644
index 00000000..a040769c
--- /dev/null
+++ b/src/main/java/com/example/demo/enums/QuestionType.java
@@ -0,0 +1,4 @@
+package com.example.demo.enums;
+
+public enum QuestionType {
+}
diff --git a/src/main/java/com/example/demo/mapper/BeanMapper.java b/src/main/java/com/example/demo/mapper/BeanMapper.java
index 424de9bd..4d886e17 100644
--- a/src/main/java/com/example/demo/mapper/BeanMapper.java
+++ b/src/main/java/com/example/demo/mapper/BeanMapper.java
@@ -4,20 +4,26 @@ import com.example.demo.domain.AssessmentLevel;
 import com.example.demo.domain.Attachment;
 import com.example.demo.domain.BaseLevel;
 import com.example.demo.domain.DecisionMatrixRow;
-import com.example.demo.domain.Task;
 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.dto.AssessmentLevelDto;
 import com.example.demo.dto.AttachmentDto;
 import com.example.demo.dto.BaseLevelDto;
 import com.example.demo.dto.DecisionMatrixRowDto;
-import com.example.demo.dto.TaskCreateDto;
-import com.example.demo.dto.TaskDto;
-import com.example.demo.dto.TaskUpdateDto;
 import com.example.demo.dto.InfoLevelCreateDto;
 import com.example.demo.dto.InfoLevelDto;
 import com.example.demo.dto.InfoLevelUpdateDto;
 import com.example.demo.dto.PhaseLevelDto;
+import com.example.demo.dto.QuestionChoiceDto;
+import com.example.demo.dto.QuestionDto;
+import com.example.demo.dto.QuestionnaireLevelDto;
+import com.example.demo.dto.TaskCreateDto;
+import com.example.demo.dto.TaskDto;
+import com.example.demo.dto.TaskUpdateDto;
 import com.example.demo.dto.input.GameDefinitionCreateDto;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
@@ -40,6 +46,8 @@ public interface BeanMapper {
             baseLevelDto = toDto((InfoLevel) baseLevel);
         } else if (baseLevel instanceof Task) {
             baseLevelDto = toDto((Task) baseLevel);
+        } else if (baseLevel instanceof QuestionnaireLevel) {
+            baseLevelDto = toDto((QuestionnaireLevel) baseLevel);
         } else {
             throw new RuntimeException("Unknown level type " + baseLevel.getClass().getName());
         }
@@ -92,7 +100,8 @@ public interface BeanMapper {
     InfoLevel updateInfoLevel(@MappingTarget InfoLevel infoLevel, GameDefinitionCreateDto gameDefinitionCreateDto);
 
     @Mapping(target = "phaseLevel", ignore = true)
-    @Mapping(target = "attachments", ignore = true) // TODO not really sure about this
+    @Mapping(target = "attachments", ignore = true)
+        // TODO not really sure about this
     Task updateTask(@MappingTarget Task task, GameDefinitionCreateDto gameDefinitionCreateDto);
 
     @Mapping(target = "subLevels", ignore = true)
@@ -113,4 +122,16 @@ public interface BeanMapper {
     DecisionMatrixRow toEntity(DecisionMatrixRowDto decisionMatrixRowDto);
 
     DecisionMatrixRowDto toDto(DecisionMatrixRow decisionMatrixRow);
+
+    QuestionChoice toEntity(QuestionChoiceDto questionChoiceDto);
+
+    QuestionChoiceDto toDto(QuestionChoice questionChoice);
+
+    Question toEntity(QuestionDto questionDto);
+
+    QuestionDto toDto(Question question);
+
+    QuestionnaireLevel toEntity(QuestionnaireLevelDto questionnaireLevelDto);
+
+    QuestionnaireLevelDto toDto(QuestionnaireLevel questionnaireLevel);
 }
diff --git a/src/main/java/com/example/demo/repository/QuestionChoiceRepository.java b/src/main/java/com/example/demo/repository/QuestionChoiceRepository.java
new file mode 100644
index 00000000..b7d14cd0
--- /dev/null
+++ b/src/main/java/com/example/demo/repository/QuestionChoiceRepository.java
@@ -0,0 +1,12 @@
+package com.example.demo.repository;
+
+import com.example.demo.domain.QuestionChoice;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+public interface QuestionChoiceRepository extends JpaRepository<QuestionChoice, Long> {
+
+    @Query("SELECT COALESCE(MAX(q.order), -1) FROM QuestionChoice q WHERE q.question.id = :questionId")
+    Integer getCurrentMaxOrder(@Param("questionId") Long questionId);
+}
diff --git a/src/main/java/com/example/demo/repository/QuestionRepository.java b/src/main/java/com/example/demo/repository/QuestionRepository.java
new file mode 100644
index 00000000..9fb220af
--- /dev/null
+++ b/src/main/java/com/example/demo/repository/QuestionRepository.java
@@ -0,0 +1,12 @@
+package com.example.demo.repository;
+
+import com.example.demo.domain.Question;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+public interface QuestionRepository extends JpaRepository<Question, Long> {
+
+    @Query("SELECT COALESCE(MAX(q.order), -1) FROM Question q WHERE q.questionnaireLevel.id = :questionnaireId")
+    Integer getCurrentMaxOrder(@Param("questionnaireId") Long questionnaireId);
+}
diff --git a/src/main/java/com/example/demo/repository/QuestionnaireLevelRepository.java b/src/main/java/com/example/demo/repository/QuestionnaireLevelRepository.java
new file mode 100644
index 00000000..cbd04783
--- /dev/null
+++ b/src/main/java/com/example/demo/repository/QuestionnaireLevelRepository.java
@@ -0,0 +1,9 @@
+package com.example.demo.repository;
+
+import com.example.demo.domain.QuestionnaireLevel;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+public interface QuestionnaireLevelRepository extends JpaRepository<QuestionnaireLevel, Long> {
+}
diff --git a/src/main/java/com/example/demo/service/LevelOperationsService.java b/src/main/java/com/example/demo/service/LevelOperationsService.java
index da3cdfb9..429823d9 100644
--- a/src/main/java/com/example/demo/service/LevelOperationsService.java
+++ b/src/main/java/com/example/demo/service/LevelOperationsService.java
@@ -4,12 +4,15 @@ import com.example.demo.domain.BaseLevel;
 import com.example.demo.domain.Task;
 import com.example.demo.domain.InfoLevel;
 import com.example.demo.dto.BaseLevelDto;
+import com.example.demo.dto.QuestionChoiceDto;
+import com.example.demo.dto.QuestionDto;
 import com.example.demo.dto.TaskDto;
 import com.example.demo.dto.TaskUpdateDto;
 import com.example.demo.dto.InfoLevelUpdateDto;
-import com.example.demo.dto.input.LevelType;
+import com.example.demo.enums.LevelType;
 import com.example.demo.mapper.BeanMapper;
 import com.example.demo.repository.BaseLevelRepository;
+import com.example.demo.repository.QuestionChoiceRepository;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -28,12 +31,21 @@ public class LevelOperationsService {
     @Autowired
     private AssessmentLevelService assessmentLevelService;
 
+    @Autowired
+    private QuestionnaireLevelService questionnaireLevelService;
+
     @Autowired
     private PhaseLevelService phaseLevelService;
 
     @Autowired
     private TaskService taskService;
 
+    @Autowired
+    private QuestionService questionService;
+
+    @Autowired
+    private QuestionChoiceService questionChoiceService;
+
     public void swapLevelsOrder(Long levelIdFrom, Long levelIdTo) {
         Optional<BaseLevel> levelFrom = baseLevelRepository.findById(levelIdFrom);
         Optional<BaseLevel> levelTo = baseLevelRepository.findById(levelIdTo);
@@ -75,6 +87,8 @@ public class LevelOperationsService {
             baseLevelDto = infoLevelService.createDefaultInfoLevel(trainingDefinitionId);
         } else if (levelType.equals(LevelType.assessment)) {
             baseLevelDto = assessmentLevelService.createDefaultAssessmentLevel(trainingDefinitionId);
+        } else if (levelType.equals(LevelType.questionnaire)) {
+            baseLevelDto = questionnaireLevelService.createDefaultQuestionnaireLevel(trainingDefinitionId);
         } else {
             baseLevelDto = phaseLevelService.createDefaultPhaseLevel(trainingDefinitionId);
         }
@@ -111,4 +125,16 @@ public class LevelOperationsService {
         Task task = BeanMapper.INSTANCE.toEntity(taskUpdateDto);
         taskService.updateTask(task);
     }
+
+    public QuestionDto createQuestion(Long questionnaireId) {
+        QuestionDto createdQuestion = questionService.createDefaultQuestion(questionnaireId);
+
+        return createdQuestion;
+    }
+
+    public QuestionChoiceDto createQuestionChoice(Long questionId) {
+        QuestionChoiceDto createdQuestionChoice = questionChoiceService.createDefaultQuestionChoice(questionId);
+
+        return createdQuestionChoice;
+    }
 }
diff --git a/src/main/java/com/example/demo/service/QuestionChoiceService.java b/src/main/java/com/example/demo/service/QuestionChoiceService.java
new file mode 100644
index 00000000..51a65589
--- /dev/null
+++ b/src/main/java/com/example/demo/service/QuestionChoiceService.java
@@ -0,0 +1,41 @@
+package com.example.demo.service;
+
+import com.example.demo.domain.Question;
+import com.example.demo.domain.QuestionChoice;
+import com.example.demo.domain.QuestionnaireLevel;
+import com.example.demo.dto.QuestionChoiceDto;
+import com.example.demo.dto.QuestionDto;
+import com.example.demo.mapper.BeanMapper;
+import com.example.demo.repository.QuestionChoiceRepository;
+import com.example.demo.repository.QuestionRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+@Service
+public class QuestionChoiceService {
+
+    @Autowired
+    private QuestionRepository questionRepository;
+
+    @Autowired
+    private QuestionChoiceRepository questionChoiceRepository;
+
+    public QuestionChoiceDto createDefaultQuestionChoice(Long questionId) {
+        Optional<Question> question = questionRepository.findById(questionId);
+        if (question.isEmpty()) {
+            // TODO return 404
+            return null;
+        }
+
+        QuestionChoice questionChoice = new QuestionChoice();
+        questionChoice.setText("Title of question choice");
+        questionChoice.setQuestion(question.get());
+        questionChoice.setOrder(questionChoiceRepository.getCurrentMaxOrder(questionId) + 1);
+
+        QuestionChoice persistedEntity = questionChoiceRepository.save(questionChoice);
+
+        return BeanMapper.INSTANCE.toDto(persistedEntity);
+    }
+}
diff --git a/src/main/java/com/example/demo/service/QuestionService.java b/src/main/java/com/example/demo/service/QuestionService.java
new file mode 100644
index 00000000..faed7120
--- /dev/null
+++ b/src/main/java/com/example/demo/service/QuestionService.java
@@ -0,0 +1,42 @@
+package com.example.demo.service;
+
+import com.example.demo.domain.PhaseLevel;
+import com.example.demo.domain.Question;
+import com.example.demo.domain.QuestionnaireLevel;
+import com.example.demo.domain.Task;
+import com.example.demo.dto.QuestionDto;
+import com.example.demo.dto.TaskDto;
+import com.example.demo.mapper.BeanMapper;
+import com.example.demo.repository.QuestionRepository;
+import com.example.demo.repository.QuestionnaireLevelRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+@Service
+public class QuestionService {
+
+    @Autowired
+    private QuestionnaireLevelRepository questionnaireLevelRepository;
+
+    @Autowired
+    private QuestionRepository questionRepository;
+
+    public QuestionDto createDefaultQuestion(Long questionnaireId) {
+        Optional<QuestionnaireLevel> questionnaireLevel = questionnaireLevelRepository.findById(questionnaireId);
+        if (questionnaireLevel.isEmpty()) {
+            // TODO return 404
+            return null;
+        }
+
+        Question question = new Question();
+        question.setText("Title of question");
+        question.setQuestionnaireLevel(questionnaireLevel.get());
+        question.setOrder(questionRepository.getCurrentMaxOrder(questionnaireId) + 1);
+
+        Question persistedEntity = questionRepository.save(question);
+
+        return BeanMapper.INSTANCE.toDto(persistedEntity);
+    }
+}
diff --git a/src/main/java/com/example/demo/service/QuestionnaireLevelService.java b/src/main/java/com/example/demo/service/QuestionnaireLevelService.java
new file mode 100644
index 00000000..1e693a21
--- /dev/null
+++ b/src/main/java/com/example/demo/service/QuestionnaireLevelService.java
@@ -0,0 +1,32 @@
+package com.example.demo.service;
+
+import com.example.demo.domain.AssessmentLevel;
+import com.example.demo.domain.QuestionnaireLevel;
+import com.example.demo.dto.QuestionnaireLevelDto;
+import com.example.demo.mapper.BeanMapper;
+import com.example.demo.repository.BaseLevelRepository;
+import com.example.demo.repository.QuestionnaireLevelRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class QuestionnaireLevelService {
+
+    @Autowired
+    private QuestionnaireLevelRepository questionnaireLevelRepository;
+
+    @Autowired
+    private BaseLevelRepository baseLevelRepository;
+
+    public QuestionnaireLevelDto createDefaultQuestionnaireLevel(Long trainingDefinitionId) {
+
+        QuestionnaireLevel questionnaireLevel =new QuestionnaireLevel();
+        questionnaireLevel.setTitle("Title of questionnaire level");
+        questionnaireLevel.setTrainingDefinitionId(trainingDefinitionId);
+        questionnaireLevel.setOrder(baseLevelRepository.getCurrentMaxOrder(trainingDefinitionId) + 1);
+
+        QuestionnaireLevel persistedEntity = questionnaireLevelRepository.save(questionnaireLevel);
+
+        return BeanMapper.INSTANCE.toDto(persistedEntity);
+    }
+}
-- 
GitLab