diff --git a/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java b/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java index 98202978a899dcd4850fdf3afc9d2d25d8dce9b2..53eb83ee64a7ef00220d2a9b2ea3580ff46f6862 100644 --- a/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java +++ b/src/main/java/com/example/demo/controller/AdaptiveTrainingDefinitionsRestController.java @@ -228,21 +228,21 @@ public class AdaptiveTrainingDefinitionsRestController { levelOperationsService.updateQuestionnaire(questionUpdateDto); } - @ApiOperation(httpMethod = "PUT", - value = "Update question", - nickname = "updateQuestion", - consumes = MediaType.APPLICATION_JSON_VALUE - ) - @ApiResponses(value = { - @ApiResponse(code = 200, message = "Question updated"), - @ApiResponse(code = 500, message = "Unexpected application error") - }) - @PutMapping(path = "/questions") - public void updateQuestion( - @ApiParam(value = "Question to be updated") @RequestBody QuestionUpdateDto questionUpdateDto) { - - levelOperationsService.updateQuestion(questionUpdateDto); - } +// @ApiOperation(httpMethod = "PUT", +// value = "Update question", +// nickname = "updateQuestion", +// consumes = MediaType.APPLICATION_JSON_VALUE +// ) +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "Question updated"), +// @ApiResponse(code = 500, message = "Unexpected application error") +// }) +// @PutMapping(path = "/questions") +// public void updateQuestion( +// @ApiParam(value = "Question to be updated") @RequestBody QuestionUpdateDto questionUpdateDto) { +// +// levelOperationsService.updateQuestion(questionUpdateDto); +// } @ApiOperation(httpMethod = "DELETE", value = "Delete a specified question", diff --git a/src/main/java/com/example/demo/controller/PhasesController.java b/src/main/java/com/example/demo/controller/PhasesController.java index ac3ce30b428c84e46c9f4549915329df6e0e5883..071758567f860e0eb222023afe8c4100dfa099dc 100644 --- a/src/main/java/com/example/demo/controller/PhasesController.java +++ b/src/main/java/com/example/demo/controller/PhasesController.java @@ -6,6 +6,10 @@ import com.example.demo.dto.InfoLevelUpdateDto; import com.example.demo.dto.PhaseCreateDTO; import com.example.demo.dto.PhaseLevelDto; import com.example.demo.dto.PhaseLevelUpdateDto; +import com.example.demo.dto.QuestionDto; +import com.example.demo.dto.QuestionUpdateDto; +import com.example.demo.dto.QuestionnaireLevelDto; +import com.example.demo.dto.QuestionnaireUpdateDto; import com.example.demo.facade.TrainingPhaseFacade; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -180,6 +184,29 @@ public class PhasesController { return new ResponseEntity<>(updatedTrainingPhase, HttpStatus.OK); } + @ApiOperation(httpMethod = "PUT", + value = "Update questionnaire phase", + nickname = "updateQuestion", + consumes = MediaType.APPLICATION_JSON_VALUE + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Questionnaire phase updated"), + @ApiResponse(code = 500, message = "Unexpected application error") + }) + @PutMapping(path = "/{phaseId}/questionnaire") + public ResponseEntity<QuestionnaireLevelDto> updateQuestionnairePhase( + @ApiParam(value = "Training definition ID", required = true) + @PathVariable(name = "definitionId") Long definitionId, + @ApiParam(value = "Phase ID", required = true) + @PathVariable("phaseId") Long phaseId, + @ApiParam(value = "Questionnaire to be updated") + @RequestBody @Valid QuestionnaireUpdateDto questionnaireUpdateDto) { + + QuestionnaireLevelDto updatedQuestionnairePhase = trainingPhaseFacade.updateQuestionnairePhase(definitionId, phaseId, questionnaireUpdateDto); + + return new ResponseEntity<>(updatedQuestionnairePhase, HttpStatus.OK); + } + @ApiOperation(httpMethod = "PUT", value = "Move phase to specified order", nickname = "movePhaseToSpecifiedOrder", diff --git a/src/main/java/com/example/demo/domain/Question.java b/src/main/java/com/example/demo/domain/Question.java index d15c6056a221a024a959f080d7639ee047a944f0..ae5b73065590834b4a8a7c82583a8d81df18598b 100644 --- a/src/main/java/com/example/demo/domain/Question.java +++ b/src/main/java/com/example/demo/domain/Question.java @@ -4,18 +4,21 @@ import com.example.demo.enums.QuestionType; import javax.persistence.CascadeType; import javax.persistence.Column; -import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OrderBy; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; @Entity public class Question { @@ -26,17 +29,11 @@ public class Question { @Enumerated(EnumType.STRING) private QuestionType questionType; - private String text; - private Integer points; - private Integer penalty; - private boolean required; - // TODO this is a Potemkin village before the consultation. Proper ManyToMany relation should be used here - @ElementCollection - private List<Long> relatedPhasesId; + private String text; - @Column(name = "order_in_questionnaire", nullable = false) - private Integer order; + @Column(name = "order_in_questionnaire") + private int order; @ManyToOne(fetch = FetchType.LAZY) private QuestionnaireLevel questionnaireLevel; @@ -45,6 +42,9 @@ public class Question { @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) private List<QuestionChoice> choices = new ArrayList<>(); + @ManyToMany(mappedBy = "questions", fetch = FetchType.LAZY) + private Set<QuestionnairePhaseRelation> questionnairePhaseRelations = new HashSet<>(); + public Long getId() { return id; } @@ -69,35 +69,11 @@ public class Question { 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() { + public int getOrder() { return order; } - public void setOrder(Integer order) { + public void setOrder(int order) { this.order = order; } @@ -117,11 +93,15 @@ public class Question { this.choices = choices; } - public List<Long> getRelatedPhasesId() { - return relatedPhasesId; + public Set<QuestionnairePhaseRelation> getQuestionPhaseRelations() { + return Collections.unmodifiableSet(questionnairePhaseRelations); + } + + public void setQuestionPhaseRelations(Set<QuestionnairePhaseRelation> questionnairePhaseRelations) { + this.questionnairePhaseRelations = questionnairePhaseRelations; } - public void setRelatedPhasesId(List<Long> relatedPhasesId) { - this.relatedPhasesId = relatedPhasesId; + public void addQuestionPhaseRelation(QuestionnairePhaseRelation questionnairePhaseRelation) { + this.questionnairePhaseRelations.add(questionnairePhaseRelation); } } diff --git a/src/main/java/com/example/demo/domain/QuestionnaireLevel.java b/src/main/java/com/example/demo/domain/QuestionnaireLevel.java index 9049f76f311be6ecc1da91e2fa8512c50ffb1f12..f46a78cc5da880a689b8135005e2f8f69c61bb71 100644 --- a/src/main/java/com/example/demo/domain/QuestionnaireLevel.java +++ b/src/main/java/com/example/demo/domain/QuestionnaireLevel.java @@ -1,7 +1,11 @@ package com.example.demo.domain; +import com.example.demo.enums.QuestionnaireType; + import javax.persistence.CascadeType; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.OneToMany; import javax.persistence.OrderBy; @@ -10,10 +14,17 @@ import java.util.List; @Entity public class QuestionnaireLevel extends BaseLevel { + @Enumerated(EnumType.STRING) + private QuestionnaireType questionnaireType; + @OrderBy @OneToMany(mappedBy = "questionnaireLevel", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) private List<Question> questions; + @OrderBy + @OneToMany(mappedBy = "relatedPhase", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List<QuestionnairePhaseRelation> questionnairePhaseRelations; + public List<Question> getQuestions() { return questions; } @@ -21,4 +32,20 @@ public class QuestionnaireLevel extends BaseLevel { public void setQuestions(List<Question> questions) { this.questions = questions; } + + public QuestionnaireType getQuestionnaireType() { + return questionnaireType; + } + + public void setQuestionnaireType(QuestionnaireType questionnaireType) { + this.questionnaireType = questionnaireType; + } + + public List<QuestionnairePhaseRelation> getQuestionnairePhaseRelations() { + return questionnairePhaseRelations; + } + + public void setQuestionnairePhaseRelations(List<QuestionnairePhaseRelation> questionnairePhaseRelations) { + this.questionnairePhaseRelations = questionnairePhaseRelations; + } } diff --git a/src/main/java/com/example/demo/domain/QuestionnairePhaseRelation.java b/src/main/java/com/example/demo/domain/QuestionnairePhaseRelation.java new file mode 100644 index 0000000000000000000000000000000000000000..b30f4e5224efcea98f3696b4e250f5a9b4592264 --- /dev/null +++ b/src/main/java/com/example/demo/domain/QuestionnairePhaseRelation.java @@ -0,0 +1,76 @@ +package com.example.demo.domain; + +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.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import java.util.Set; + +@Entity +public class QuestionnairePhaseRelation { + + @Id + @GeneratedValue + private Long id; + + @Column(name = "order_in_questionnaire", nullable = false) + private Integer order; + + @ManyToOne(fetch = FetchType.LAZY) + private QuestionnaireLevel relatedPhase; + + @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + @JoinTable(name = "questionnaire_phase_relation_question", + joinColumns = @JoinColumn(name = "question_phase_id"), + inverseJoinColumns = @JoinColumn(name = "question_id") + ) + private Set<Question> questions; + + private int successRate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getOrder() { + return order; + } + + public void setOrder(Integer order) { + this.order = order; + } + + public QuestionnaireLevel getRelatedPhase() { + return relatedPhase; + } + + public void setRelatedPhase(QuestionnaireLevel relatedPhase) { + this.relatedPhase = relatedPhase; + } + + public Set<Question> getQuestions() { + return questions; + } + + public void setQuestions(Set<Question> questions) { + this.questions = questions; + } + + public int getSuccessRate() { + return successRate; + } + + public void setSuccessRate(int successRate) { + this.successRate = successRate; + } +} diff --git a/src/main/java/com/example/demo/enums/QuestionType.java b/src/main/java/com/example/demo/enums/QuestionType.java index 78adce7df84410883a71bb7a0b4e89cf6430913f..e0d127eea67c49accb785645cf2fd84335a809da 100644 --- a/src/main/java/com/example/demo/enums/QuestionType.java +++ b/src/main/java/com/example/demo/enums/QuestionType.java @@ -3,5 +3,5 @@ package com.example.demo.enums; public enum QuestionType { FFQ, MCQ, - EMI + RFQ } diff --git a/src/main/java/com/example/demo/enums/QuestionnaireType.java b/src/main/java/com/example/demo/enums/QuestionnaireType.java new file mode 100644 index 0000000000000000000000000000000000000000..c7b23f385004694a001964edd08152fe5ccc9208 --- /dev/null +++ b/src/main/java/com/example/demo/enums/QuestionnaireType.java @@ -0,0 +1,6 @@ +package com.example.demo.enums; + +public enum QuestionnaireType { + ADAPTIVE, + GENERAL +} diff --git a/src/main/java/com/example/demo/facade/TrainingPhaseFacade.java b/src/main/java/com/example/demo/facade/TrainingPhaseFacade.java index de568cb7ce783ecc365ae2074df3b0183ae81f0c..14d83036a11afb927c6e06cd12a565f199364cd0 100644 --- a/src/main/java/com/example/demo/facade/TrainingPhaseFacade.java +++ b/src/main/java/com/example/demo/facade/TrainingPhaseFacade.java @@ -6,6 +6,10 @@ import com.example.demo.dto.InfoLevelUpdateDto; import com.example.demo.dto.PhaseCreateDTO; import com.example.demo.dto.PhaseLevelDto; import com.example.demo.dto.PhaseLevelUpdateDto; +import com.example.demo.dto.QuestionDto; +import com.example.demo.dto.QuestionUpdateDto; +import com.example.demo.dto.QuestionnaireLevelDto; +import com.example.demo.dto.QuestionnaireUpdateDto; import com.example.demo.enums.PhaseType; import com.example.demo.service.InfoLevelService; import com.example.demo.service.PhaseLevelService; @@ -73,6 +77,10 @@ public class TrainingPhaseFacade { return phaseLevelService.updatePhaseLevel(definitionId, phaseId, trainingPhaseUpdate); } + public QuestionnaireLevelDto updateQuestionnairePhase(Long definitionId, Long phaseId, QuestionnaireUpdateDto questionnaireUpdateDto) { + return questionnaireLevelService.updateQuestionnairePhase(definitionId, phaseId, questionnaireUpdateDto); + } + public void movePhaseToSpecifiedOrder(Long phaseIdFrom, int newPosition) { phaseService.moveLevelToSpecifiedOrder(phaseIdFrom, newPosition); } diff --git a/src/main/java/com/example/demo/service/QuestionnaireLevelService.java b/src/main/java/com/example/demo/service/QuestionnaireLevelService.java index 104d9846f7508b1d5113c7bb1eecb34eeda23ecd..0db72a0fbd96568b589637177f5b417ac43a42d7 100644 --- a/src/main/java/com/example/demo/service/QuestionnaireLevelService.java +++ b/src/main/java/com/example/demo/service/QuestionnaireLevelService.java @@ -1,10 +1,14 @@ package com.example.demo.service; import com.example.demo.domain.AssessmentLevel; +import com.example.demo.domain.BaseLevel; +import com.example.demo.domain.PhaseLevel; import com.example.demo.domain.Question; import com.example.demo.domain.QuestionnaireLevel; import com.example.demo.dto.QuestionDto; +import com.example.demo.dto.QuestionUpdateDto; import com.example.demo.dto.QuestionnaireLevelDto; +import com.example.demo.dto.QuestionnaireUpdateDto; import com.example.demo.mapper.BeanMapper; import com.example.demo.repository.BaseLevelRepository; import com.example.demo.repository.QuestionnaireLevelRepository; @@ -12,6 +16,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import java.util.Optional; @@ -55,4 +60,25 @@ public class QuestionnaireLevelService { return BeanMapper.INSTANCE.toDto(savedEntity); } + + public QuestionnaireLevelDto updateQuestionnairePhase(Long definitionId, Long phaseId, QuestionnaireUpdateDto questionnaireUpdateDto) { + QuestionnaireLevel questionnaireLevel = BeanMapper.INSTANCE.toEntity(questionnaireUpdateDto); + questionnaireLevel.setId(phaseId); + + QuestionnaireLevel persistedQuestionnairePhase = questionnaireLevelRepository.findById(questionnaireLevel.getId()) + .orElseThrow(() -> new RuntimeException("Questionnaire phase was not found")); + // TODO throw proper exception once kypo2-training is migrated + + // TODO add check to trainingDefinitionId and phaseId (field structure will be probably changed); + + + questionnaireLevel.setTrainingDefinitionId(persistedQuestionnairePhase.getTrainingDefinitionId()); + questionnaireLevel.setOrder(persistedQuestionnairePhase.getOrder()); + + // TODO questions, their choices and realtions among questions and training phases must be set here + + QuestionnaireLevel savedEntity = questionnaireLevelRepository.save(questionnaireLevel); + + return BeanMapper.INSTANCE.toDto(savedEntity); + } }