diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/AccessToken.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/AccessToken.java index c75e7db7572d86a8fdbf3619f3b2471d65ede1ca..a05b7ccc53e8bbd9cd993780f0e58f8604ce2d9f 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/AccessToken.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/AccessToken.java @@ -19,25 +19,11 @@ import java.util.Objects; public class AccessToken implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "accessTokenGenerator" - ) - @SequenceGenerator( - name = "accessTokenGenerator", - sequenceName = "access_token_seq" - ) - @Column( - name = "access_token_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accessTokenGenerator") + @SequenceGenerator(name = "accessTokenGenerator", sequenceName = "access_token_seq") + @Column(name = "access_token_id", nullable = false, unique = true) private Long id; - @Column( - name = "access_token", - nullable = false, - unique = true - ) + @Column(name = "access_token", nullable = false, unique = true) private String accessToken; /** diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/TRAcquisitionLock.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/TRAcquisitionLock.java index 542af91859d598c59e01ed85425c968952f10be0..4daf5572c97a0d7ca0ba50505b69ccedc7bff5db 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/TRAcquisitionLock.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/TRAcquisitionLock.java @@ -20,19 +20,9 @@ import java.util.Objects; public class TRAcquisitionLock implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "trAcquisitionLockGenerator" - ) - @SequenceGenerator( - name = "trAcquisitionLockGenerator", - sequenceName = "tr_acquisition_lock_seq" - ) - @Column( - name = "training_run_acquisition_lock_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "trAcquisitionLockGenerator") + @SequenceGenerator(name = "trAcquisitionLockGenerator", sequenceName = "tr_acquisition_lock_seq") + @Column(name = "training_run_acquisition_lock_id", nullable = false, unique = true) private Long id; @Column(name = "participant_ref_id") private Long participantRefId; diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/User.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/User.java index 425793ae54b5bf2c13e6ec67c4cff06f5a321313..fbbb3c6458dfe24815cbea1b3ca1939a71fa70a4 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/User.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/User.java @@ -35,24 +35,11 @@ import java.util.Set; public class User implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "userGenerator" - ) - @SequenceGenerator( - name = "userGenerator", - sequenceName = "user_seq" - ) - @Column( - name = "user_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "userGenerator") + @SequenceGenerator(name = "userGenerator", sequenceName = "user_seq") + @Column(name = "user_id", nullable = false, unique = true) private Long id; - @Column( - name = "user_ref_id", - nullable = false - ) + @Column(name = "user_ref_id", nullable = false) private Long userRefId; @ManyToMany( mappedBy = "organizers", diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/DecisionMatrixRow.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/DecisionMatrixRow.java index 1547a97b329e7f359aea54ee5f7c42f7258aade9..89307e8360074825e0bfa465af231ebc80cd0c3d 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/DecisionMatrixRow.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/DecisionMatrixRow.java @@ -9,24 +9,11 @@ import java.io.Serializable; public class DecisionMatrixRow implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "decisionMatrixRowGenerator" - ) - @SequenceGenerator( - name = "decisionMatrixRowGenerator", - sequenceName = "decision_matrix_row_seq" - ) - @Column( - name = "decision_matrix_row_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "decisionMatrixRowGenerator") + @SequenceGenerator(name = "decisionMatrixRowGenerator", sequenceName = "decision_matrix_row_seq") + @Column(name = "decision_matrix_row_id", nullable = false, unique = true) private Long id; - @Column( - name = "order_in_training_phase", - nullable = false - ) + @Column(name = "order_in_training_phase", nullable = false) private int order; @Column(name = "assessment_answered") private double assessmentAnswered; diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/Task.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/Task.java index 44f9689e9f1c582d3c5d41416c26afdab79e82cf..1eca9d071085dbcc46eb58b575478f4c971aad46 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/Task.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/Task.java @@ -9,19 +9,9 @@ import java.io.Serializable; public class Task implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "taskGenerator" - ) - @SequenceGenerator( - name = "taskGenerator", - sequenceName = "task_seq" - ) - @Column( - name = "task_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "taskGenerator") + @SequenceGenerator(name = "taskGenerator", sequenceName = "task_seq") + @Column(name = "task_id", nullable = false, unique = true) private Long id; @Column(name = "title") private String title; diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/Question.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/Question.java index 5eb81827f5d8b0f2d7327987f7dc488896afdd4c..fb0848cacd311d14e68b5eda171c784bb68fed32 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/Question.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/Question.java @@ -12,19 +12,9 @@ import java.util.*; public class Question implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "questionGenerator" - ) - @SequenceGenerator( - name = "questionGenerator", - sequenceName = "question_seq" - ) - @Column( - name = "question_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "questionGenerator") + @SequenceGenerator(name = "questionGenerator", sequenceName = "question_seq") + @Column(name = "question_id", nullable = false, unique = true) private Long id; @Enumerated(EnumType.STRING) @Column(name = "question_type") diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionAnswer.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionAnswer.java index 77e206a2085051fb00009cd1d2c7366d0bbcaa23..3c3f204c4abc4538aeff84aee03ca344ab379335 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionAnswer.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionAnswer.java @@ -4,7 +4,9 @@ import cz.muni.ics.kypo.training.adaptive.domain.training.TrainingRun; import javax.persistence.*; import java.io.Serializable; -import java.util.Objects; +import java.util.HashSet; +import java.util.List; +import java.util.Set; @Entity @Table(name = "question_answer") @@ -20,8 +22,13 @@ public class QuestionAnswer implements Serializable { @MapsId("trainingRunId") @JoinColumn(name = "training_run_id") private TrainingRun trainingRun; + @ElementCollection + @CollectionTable( + name = "question_answers", + joinColumns = {@JoinColumn(name = "training_run_id"), @JoinColumn(name = "question_id")} + ) @Column(name = "answer") - private String answer; + private Set<String> answers = new HashSet<>(); public QuestionAnswer() { this.questionAnswerId = new QuestionAnswerId(); @@ -59,20 +66,19 @@ public class QuestionAnswer implements Serializable { this.trainingRun = trainingRun; } - public String getAnswer() { - return answer; + public Set<String> getAnswers() { + return answers; } - public void setAnswer(String answer) { - this.answer = answer; + public void setAnswers(Set<String> answers) { + this.answers = answers; } - @Override public String toString() { return "QuestionAnswer{" + "questionAnswerId=" + this.getQuestionAnswerId() + - ", answer='" + this.getQuestionAnswerId() + '\'' + + ", answers='" + this.getAnswers() + '\'' + '}'; } } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionChoice.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionChoice.java index c7304d6de0cedd47b6dfc4bbe68763c5d60d2829..098265333fd6c09ec44a28599fa03386df52ebd0 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionChoice.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionChoice.java @@ -8,19 +8,9 @@ import java.io.Serializable; public class QuestionChoice implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "questionChoiceGenerator" - ) - @SequenceGenerator( - name = "questionChoiceGenerator", - sequenceName = "question_choice_seq" - ) - @Column( - name = "question_choice_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "questionChoiceGenerator") + @SequenceGenerator(name = "questionChoiceGenerator", sequenceName = "question_choice_seq") + @Column(name = "question_choice_id", nullable = false, unique = true) private Long id; @Column(name = "text") private String text; diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionPhaseRelation.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionPhaseRelation.java index c602963887cd3da47c33c8062eb0e7f89194bb58..d7c5c527717558c7402e7e56acd835cd4c80fbed 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionPhaseRelation.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionPhaseRelation.java @@ -13,24 +13,11 @@ import java.util.Set; public class QuestionPhaseRelation implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "questionPhaseGenerator" - ) - @SequenceGenerator( - name = "questionPhaseGenerator", - sequenceName = "question_phase_seq" - ) - @Column( - name = "question_phase_relation_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "questionPhaseGenerator") + @SequenceGenerator(name = "questionPhaseGenerator", sequenceName = "question_phase_seq") + @Column(name = "question_phase_relation_id", nullable = false, unique = true) private Long id; - @Column( - name = "order_in_questionnaire", - nullable = false - ) + @Column(name = "order_in_questionnaire", nullable = false) private Integer order; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "questionnaire_phase_id") diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionPhaseResult.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionsPhaseRelationResult.java similarity index 69% rename from src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionPhaseResult.java rename to src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionsPhaseRelationResult.java index 334933b38d84983912f87718447ef4806e86a0c4..9cd42f8b9555d0407aa374fbabbdc7a5f40df74c 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionPhaseResult.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/QuestionsPhaseRelationResult.java @@ -7,29 +7,19 @@ import javax.persistence.*; import java.io.Serializable; @Entity -@Table(name = "question_phase_result") -public class QuestionPhaseResult implements Serializable { +@Table(name = "questions_phase_relation_result") +public class QuestionsPhaseRelationResult implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "questionPhaseResultGenerator" - ) - @SequenceGenerator( - name = "questionPhaseResultGenerator", - sequenceName = "question_phase_result_seq" - ) - @Column( - name = "question_phase_result_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "questionsPhaseRelationResultGenerator") + @SequenceGenerator(name = "questionsPhaseRelationResultGenerator", sequenceName = "questions_phase_relation_result_seq") + @Column(name = "questions_phase_relation_result_id", nullable = false, unique = true) private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "training_run_id") private TrainingRun trainingRun; @Column(name = "achieved_result") - private int achievedResult; + private double achievedResult; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "question_phase_relation_id") private QuestionPhaseRelation questionPhaseRelation; @@ -50,11 +40,11 @@ public class QuestionPhaseResult implements Serializable { this.trainingRun = trainingRun; } - public int getAchievedResult() { + public double getAchievedResult() { return achievedResult; } - public void setAchievedResult(int achievedResult) { + public void setAchievedResult(double achievedResult) { this.achievedResult = achievedResult; } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/TrainingPhaseQuestionsFulfillment.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/TrainingPhaseQuestionsFulfillment.java new file mode 100644 index 0000000000000000000000000000000000000000..599d5fff962e9e41c933948ee5ca227107265fd2 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/phase/questions/TrainingPhaseQuestionsFulfillment.java @@ -0,0 +1,76 @@ +package cz.muni.ics.kypo.training.adaptive.domain.phase.questions; + + +import cz.muni.ics.kypo.training.adaptive.domain.phase.TrainingPhase; +import cz.muni.ics.kypo.training.adaptive.domain.training.TrainingRun; + +import javax.persistence.*; +import java.io.Serializable; + +@Entity +@Table(name = "adaptive_questions_fulfillment") +public class TrainingPhaseQuestionsFulfillment implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "adaptiveQuestionsFulfillmentGenerator") + @SequenceGenerator(name = "adaptiveQuestionsFulfillmentGenerator", sequenceName = "adaptive_questions_fulfillment_seq") + @Column(name = "adaptive_questions_fulfillment_id", nullable = false, unique = true) + private Long id; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "training_run_id") + private TrainingRun trainingRun; + @Column(name = "fulfilled") + private boolean fulfilled; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "training_phase_id") + private TrainingPhase trainingPhase; + + public TrainingPhaseQuestionsFulfillment() { + } + + public TrainingPhaseQuestionsFulfillment(TrainingRun trainingRun, TrainingPhase trainingPhase, boolean fulfilled) { + this.trainingRun = trainingRun; + this.trainingPhase = trainingPhase; + this.fulfilled = fulfilled; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public TrainingRun getTrainingRun() { + return trainingRun; + } + + public void setTrainingRun(TrainingRun trainingRun) { + this.trainingRun = trainingRun; + } + + public boolean isFulfilled() { + return fulfilled; + } + + public void setFulfilled(boolean fulfilled) { + this.fulfilled = fulfilled; + } + + public TrainingPhase getTrainingPhase() { + return trainingPhase; + } + + public void setTrainingPhase(TrainingPhase trainingPhase) { + this.trainingPhase = trainingPhase; + } + + @Override + public String toString() { + return "AdaptiveQuestionsFulfillment{" + + "id=" + id + + ", fulfilled=" + fulfilled + + '}'; + } +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingDefinition.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingDefinition.java index e404907add4b8a3343ac92a2a4fdee190cbf1cf2..3a6f98439700aa577ec47f19298fb189a6028fc0 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingDefinition.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingDefinition.java @@ -29,24 +29,11 @@ import java.util.*; public class TrainingDefinition implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "trainingDefinitionGenerator" - ) - @SequenceGenerator( - name = "trainingDefinitionGenerator", - sequenceName = "training_definition_seq" - ) - @Column( - name = "training_definition_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "trainingDefinitionGenerator") + @SequenceGenerator(name = "trainingDefinitionGenerator", sequenceName = "training_definition_seq") + @Column(name = "training_definition_id", nullable = false, unique = true) private Long id; - @Column( - name = "title", - nullable = false - ) + @Column(name = "title", nullable = false) private String title; @Column(name = "description") private String description; @@ -54,11 +41,7 @@ public class TrainingDefinition implements Serializable { private String[] prerequisites; @Column(name = "outcomes") private String[] outcomes; - @Column( - name = "state", - length = 128, - nullable = false - ) + @Column(name = "state", length = 128, nullable = false) @Enumerated(EnumType.STRING) private TDState state; @ManyToMany( diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java index b126438140df3df51d5c53d62889653d08866539..8083430eb8cede2988d3aa5df4b46c2ee944deaa 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java @@ -73,42 +73,19 @@ import java.util.Set; public class TrainingInstance implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "trainingInstanceGenerator" - ) - @SequenceGenerator( - name = "trainingInstanceGenerator", - sequenceName = "training_instance_seq" - ) - @Column( - name = "training_instance_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "trainingInstanceGenerator") + @SequenceGenerator(name = "trainingInstanceGenerator", sequenceName = "training_instance_seq") + @Column(name = "training_instance_id", nullable = false, unique = true) private Long id; - @Column( - name = "start_time", - nullable = false - ) + @Column(name = "start_time", nullable = false) private LocalDateTime startTime; - @Column( - name = "end_time", - nullable = false - ) + @Column(name = "end_time", nullable = false) private LocalDateTime endTime; - @Column( - name = "title", - nullable = false - ) + @Column(name = "title", nullable = false) private String title; @Column(name = "pool_id") private Long poolId; - @Column( - name = "access_token", - nullable = false, - unique = true - ) + @Column(name = "access_token", nullable = false, unique = true) private String accessToken; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "training_definition_id") diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingRun.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingRun.java index 8acd50c447d0ee1f10c9527a5c60ff5b201a8e31..ac88a6f1092a6d31cae85005303531267fb70ee5 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingRun.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingRun.java @@ -96,46 +96,20 @@ import java.util.Objects; public class TrainingRun implements Serializable { @Id - @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "trainingRunGenerator" - ) - @SequenceGenerator( - name = "trainingRunGenerator", - sequenceName = "training_run_seq" - ) - @Column( - name = "training_run_id", - nullable = false, - unique = true - ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "trainingRunGenerator") + @SequenceGenerator(name = "trainingRunGenerator", sequenceName = "training_run_seq") + @Column(name = "training_run_id", nullable = false, unique = true) private Long id; - @Column( - name = "start_time", - nullable = false - ) + @Column(name = "start_time", nullable = false) private LocalDateTime startTime; - @Column( - name = "end_time", - nullable = false - ) + @Column(name = "end_time", nullable = false) private LocalDateTime endTime; - @Column( - name = "state", - length = 128, - nullable = false - ) + @Column(name = "state", length = 128, nullable = false) @Enumerated(EnumType.STRING) private TRState state; - @Column( - name = "incorrect_answer_count", - nullable = false - ) + @Column(name = "incorrect_answer_count", nullable = false) private int incorrectAnswerCount; - @Column( - name = "solution_taken", - nullable = false - ) + @Column(name = "solution_taken", nullable = false) private boolean solutionTaken; @ManyToOne( fetch = FetchType.LAZY, @@ -155,10 +129,7 @@ public class TrainingRun implements Serializable { @Column(name = "sandbox_instance_ref_id") private Long sandboxInstanceRefId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn( - name = "user_id", - nullable = false - ) + @JoinColumn(name = "user_id", nullable = false) private User participantRef; @Column(name = "phase_answered") private boolean phaseAnswered; diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/QuestionAnswerDTO.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/QuestionAnswerDTO.java index 0cdc0b6d1525738fd99a017aea3da9ed918ade41..436dba2fca49efb43fa5e1f1b9588d9ace4b25da 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/QuestionAnswerDTO.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/QuestionAnswerDTO.java @@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import javax.validation.constraints.NotNull; +import java.util.Set; + @ApiModel( value = "QuestionAnswerDTO" ) @@ -13,7 +15,7 @@ public class QuestionAnswerDTO { @NotNull(message = "ID of the answered question must not be null") private Long questionId; @ApiModelProperty(value = "Answer to the question", example = "An answer") - private String answer; + private Set<String> answers; public Long getQuestionId() { return questionId; @@ -23,20 +25,19 @@ public class QuestionAnswerDTO { this.questionId = questionId; } - public String getAnswer() { - return answer; + public Set<String> getAnswers() { + return answers; } - public void setAnswer(String answer) { - this.answer = answer; + public void setAnswers(Set<String> answers) { + this.answers = answers; } - @Override public String toString() { return "QuestionAnswerDTO{" + "questionId=" + questionId + - ", answer='" + answer + '\'' + + ", answers='" + answers + '\'' + '}'; } } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/view/QuestionChoiceViewDTO.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/view/QuestionChoiceViewDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..4121b49e40ba0ec365c2711aa97a86081236c800 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/view/QuestionChoiceViewDTO.java @@ -0,0 +1,67 @@ +package cz.muni.ics.kypo.training.adaptive.dto.questionnaire.view; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Objects; + +public class QuestionChoiceViewDTO { + + @ApiModelProperty(value = "Question choice ID. Leave blank if new choice is added", required = true, example = "1") + private Long id; + @ApiModelProperty(value = "Short description of question choice", required = true, example = "An answer") + @NotEmpty(message = "Task title must not be blank") + private String text; + @ApiModelProperty(value = "Order of question choice", required = true, example = "0") + @NotNull(message = "Question choice order must be specified") + 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 Integer getOrder() { + return order; + } + + public void setOrder(Integer order) { + this.order = order; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + QuestionChoiceViewDTO that = (QuestionChoiceViewDTO) o; + return Objects.equals(id, that.id) && + Objects.equals(text, that.text) && + Objects.equals(order, that.order); + } + + @Override + public int hashCode() { + return Objects.hash(id, text, order); + } + + @Override + public String toString() { + return "QuestionChoiceDTO{" + + "id=" + id + + ", text='" + text + '\'' + + ", order=" + order + + '}'; + } +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/view/QuestionViewDTO.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/view/QuestionViewDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..3fe32fb0cbf60d94e01c610b8803a49ab050222a --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/view/QuestionViewDTO.java @@ -0,0 +1,93 @@ +package cz.muni.ics.kypo.training.adaptive.dto.questionnaire.view; + +import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionChoiceDTO; +import cz.muni.ics.kypo.training.adaptive.enums.QuestionType; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Objects; + +public class QuestionViewDTO { + + @ApiModelProperty(value = "Question ID. Leave blank if a new question is added", required = true, example = "1") + private Long id; + @ApiModelProperty(value = "Order of question", required = true, example = "0") + @NotNull(message = "Question order must be specified") + private int order; + @ApiModelProperty(value = "The question that will be displayed to a player", required = true, example = "What's the capital of Canada?") + @NotEmpty(message = "Text of question must not be blank") + private String text; + @ApiModelProperty(value = "It defines the type of the question", allowableValues = "FFQ, MCQ, RFQ", required = true, example = "MCQ") + @NotNull(message = "Question type must be specified") + private QuestionType questionType; + @ApiModelProperty(value = "Choices that are distributed with the question", required = true) + private List<QuestionChoiceViewDTO> choices; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public QuestionType getQuestionType() { + return questionType; + } + + public void setQuestionType(QuestionType type) { + this.questionType = type; + } + + public List<QuestionChoiceViewDTO> getChoices() { + return choices; + } + + public void setChoices(List<QuestionChoiceViewDTO> choices) { + this.choices = choices; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof QuestionViewDTO)) return false; + QuestionViewDTO that = (QuestionViewDTO) o; + return getOrder() == that.getOrder() && + getId().equals(that.getId()) && + getText().equals(that.getText()) && + getQuestionType() == that.getQuestionType(); + } + + @Override + public int hashCode() { + return Objects.hash(getId(), getOrder(), getText()); + } + + @Override + public String toString() { + return "QuestionViewDTO{" + + "id=" + id + + ", order=" + order + + ", text='" + text + '\'' + + ", questionType=" + questionType + + '}'; + } +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/view/QuestionnairePhaseViewDTO.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/view/QuestionnairePhaseViewDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..ce035b7833ab49907a62a023b4dd4d334c8ceab0 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/questionnaire/view/QuestionnairePhaseViewDTO.java @@ -0,0 +1,54 @@ +package cz.muni.ics.kypo.training.adaptive.dto.questionnaire.view; + +import cz.muni.ics.kypo.training.adaptive.dto.AbstractPhaseDTO; +import cz.muni.ics.kypo.training.adaptive.enums.QuestionnaireType; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; +import java.util.Objects; + +public class QuestionnairePhaseViewDTO extends AbstractPhaseDTO { + + @ApiModelProperty(value = "List of questions associated with the questionnaire phase") + private List<QuestionViewDTO> questions; + @ApiModelProperty(value = "Type of questionnaire phase", allowableValues = "ADAPTIVE,GENERAL", example = "ADAPTIVE") + private QuestionnaireType questionnaireType; + + public List<QuestionViewDTO> getQuestions() { + return questions; + } + + public void setQuestions(List<QuestionViewDTO> questions) { + this.questions = questions; + } + + public QuestionnaireType getQuestionnaireType() { + return questionnaireType; + } + + public void setQuestionnaireType(QuestionnaireType questionnaireType) { + this.questionnaireType = questionnaireType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + QuestionnairePhaseViewDTO that = (QuestionnairePhaseViewDTO) o; + return Objects.equals(questions, that.questions) && + questionnaireType == that.questionnaireType; + } + + @Override + public int hashCode() { + return Objects.hash(questions, questionnaireType); + } + + @Override + public String toString() { + return "QuestionnairePhaseDTO{" + + "questions=" + questions + + ", questionnaireType=" + questionnaireType + + "} " + super.toString(); + } +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/training/view/TaskViewDTO.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/training/view/TaskViewDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..169fa6d86b0681f6931df2b0835f3b6db0792ff9 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/training/view/TaskViewDTO.java @@ -0,0 +1,99 @@ +package cz.muni.ics.kypo.training.adaptive.dto.training.view; + +import io.swagger.annotations.ApiModelProperty; + +import java.util.Objects; + +public class TaskViewDTO { + + @ApiModelProperty(value = "ID of task", required = true, example = "1") + private Long id; + @ApiModelProperty(value = "Short description of task", required = true, example = "Task title") + private String title; + @ApiModelProperty(value = "The information that are displayed to a player", required = true, example = "Capture the flag") + private String content; + @ApiModelProperty(value = "It defines the allowed number of incorrect answers submitted by the player", required = true, example = "5") + private int incorrectAnswerLimit; + @ApiModelProperty(value = "It defines whether the sandbox can be modified", example = "true") + private boolean modifySandbox; + @ApiModelProperty(value = "It defines the expected duration of sandbox change defined in seconds", example = "15") + private int sandboxChangeExpectedDuration; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public int getIncorrectAnswerLimit() { + return incorrectAnswerLimit; + } + + public void setIncorrectAnswerLimit(int incorrectAnswerLimit) { + this.incorrectAnswerLimit = incorrectAnswerLimit; + } + + public boolean isModifySandbox() { + return modifySandbox; + } + + public void setModifySandbox(boolean modifySandbox) { + this.modifySandbox = modifySandbox; + } + + public int getSandboxChangeExpectedDuration() { + return sandboxChangeExpectedDuration; + } + + public void setSandboxChangeExpectedDuration(int sandboxChangeExpectedDuration) { + this.sandboxChangeExpectedDuration = sandboxChangeExpectedDuration; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TaskViewDTO taskDTO = (TaskViewDTO) o; + return incorrectAnswerLimit == taskDTO.incorrectAnswerLimit && + modifySandbox == taskDTO.modifySandbox && + sandboxChangeExpectedDuration == taskDTO.sandboxChangeExpectedDuration && + Objects.equals(id, taskDTO.id) && + Objects.equals(title, taskDTO.title) && + Objects.equals(content, taskDTO.content); + } + + @Override + public int hashCode() { + return Objects.hash(id, title, content, incorrectAnswerLimit, modifySandbox, sandboxChangeExpectedDuration); + } + + @Override + public String toString() { + return "TaskDTO{" + + "id=" + id + + ", title='" + title + '\'' + + ", content='" + content + '\'' + + ", incorrectAnswerLimit=" + incorrectAnswerLimit + + ", modifySandbox=" + modifySandbox + + ", sandboxChangeExpectedDuration=" + sandboxChangeExpectedDuration + + '}'; + } +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/training/view/TrainingPhaseViewDTO.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/training/view/TrainingPhaseViewDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..f6f00e6d42079058a47e003848249619c241b995 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/dto/training/view/TrainingPhaseViewDTO.java @@ -0,0 +1,75 @@ +package cz.muni.ics.kypo.training.adaptive.dto.training.view; + +import cz.muni.ics.kypo.training.adaptive.dto.AbstractPhaseDTO; +import io.swagger.annotations.ApiModelProperty; + +import java.util.Objects; + +public class TrainingPhaseViewDTO extends AbstractPhaseDTO { + + @ApiModelProperty(value = "Estimated time (minutes) taken by the player to solve the training phase", example = "20") + private int estimatedDuration; + @ApiModelProperty(value = "Maximal number of allowed commands provided by played", required = true, example = "10") + private int allowedCommands; + @ApiModelProperty(value = "Maximal number of allowed wrong answers provided by played", required = true, example = "10") + private int allowedWrongAnswers; + @ApiModelProperty(value = "Task associated with the training phase", required = true) + private TaskViewDTO task; + + public int getEstimatedDuration() { + return estimatedDuration; + } + + public void setEstimatedDuration(int estimatedDuration) { + this.estimatedDuration = estimatedDuration; + } + + public int getAllowedCommands() { + return allowedCommands; + } + + public void setAllowedCommands(int allowedCommands) { + this.allowedCommands = allowedCommands; + } + + public int getAllowedWrongAnswers() { + return allowedWrongAnswers; + } + + public void setAllowedWrongAnswers(int allowedWrongAnswers) { + this.allowedWrongAnswers = allowedWrongAnswers; + } + + public TaskViewDTO getTask() { + return task; + } + + public void setTask(TaskViewDTO task) { + this.task = task; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TrainingPhaseViewDTO that = (TrainingPhaseViewDTO) o; + return estimatedDuration == that.estimatedDuration && + allowedCommands == that.allowedCommands && + allowedWrongAnswers == that.allowedWrongAnswers; + } + + @Override + public int hashCode() { + return Objects.hash(estimatedDuration, allowedCommands, allowedWrongAnswers, task); + } + + @Override + public String toString() { + return "TrainingPhaseDTO{" + + "estimatedDuration=" + estimatedDuration + + ", allowedCommands=" + allowedCommands + + ", allowedWrongAnswers=" + allowedWrongAnswers + + ", tasks=" + task + + "} " + super.toString(); + } +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingRunFacade.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingRunFacade.java index 8473568e5280749d3f4bf8472ae3e4a5b1be6c2a..64557d23765db219f377eb3b42132afb10efdc7b 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingRunFacade.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingRunFacade.java @@ -16,12 +16,8 @@ import cz.muni.ics.kypo.training.adaptive.dto.AbstractPhaseDTO; import cz.muni.ics.kypo.training.adaptive.dto.BasicPhaseInfoDTO; import cz.muni.ics.kypo.training.adaptive.dto.IsCorrectAnswerDTO; import cz.muni.ics.kypo.training.adaptive.dto.UserRefDTO; -import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionChoiceDTO; -import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionDTO; -import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionnairePhaseDTO; +import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.*; import cz.muni.ics.kypo.training.adaptive.dto.responses.PageResultResource; -import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionAnswerDTO; -import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionnairePhaseAnswersDTO; import cz.muni.ics.kypo.training.adaptive.dto.trainingrun.AccessTrainingRunDTO; import cz.muni.ics.kypo.training.adaptive.dto.trainingrun.AccessedTrainingRunDTO; import cz.muni.ics.kypo.training.adaptive.dto.trainingrun.TrainingRunByIdDTO; @@ -33,6 +29,7 @@ import cz.muni.ics.kypo.training.adaptive.mapping.TrainingRunMapper; import cz.muni.ics.kypo.training.adaptive.service.QuestionnaireEvaluationService; import cz.muni.ics.kypo.training.adaptive.service.api.UserManagementServiceApi; import cz.muni.ics.kypo.training.adaptive.service.training.TrainingRunService; +import cz.muni.ics.kypo.training.adaptive.utils.Sort; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -333,15 +330,15 @@ public class TrainingRunFacade { /** * Evaluate and store answers to questionnaire. * - * @param trainingRunId id of the Training Run. + * @param trainingRunId id of the Training Run. * @param questionnairePhaseAnswersDTO answers to questionnaire */ @PreAuthorize("hasAuthority(T(cz.muni.ics.kypo.training.adaptive.enums.RoleTypeSecurity).ROLE_ADAPTIVE_TRAINING_ADMINISTRATOR)" + "or @securityService.isTraineeOfGivenTrainingRun(#trainingRunId)") @TransactionalWO public void evaluateAnswersToQuestionnaire(Long trainingRunId, QuestionnairePhaseAnswersDTO questionnairePhaseAnswersDTO) { - Map<Long, String> questionsAnswersMapping = questionnairePhaseAnswersDTO.getAnswers().stream() - .collect(Collectors.toMap(QuestionAnswerDTO::getQuestionId, QuestionAnswerDTO::getAnswer)); + Map<Long, Set<String>> questionsAnswersMapping = questionnairePhaseAnswersDTO.getAnswers().stream() + .collect(Collectors.toMap(QuestionAnswerDTO::getQuestionId, QuestionAnswerDTO::getAnswers)); questionnaireEvaluationService.saveAndEvaluateAnswersToQuestionnaire(trainingRunId, questionsAnswersMapping); } @@ -374,13 +371,11 @@ public class TrainingRunFacade { } private List<AccessedTrainingRunDTO> sortByTitle(List<AccessedTrainingRunDTO> runs, String sortByTitle) { - if (sortByTitle != null && !sortByTitle.isBlank()) { - if (!runs.isEmpty()) { - if (sortByTitle.equals("asc")) { + if (sortByTitle != null && !sortByTitle.isBlank() && !runs.isEmpty()) { + if (sortByTitle.equals(Sort.ASC)) { runs.sort(Comparator.comparing(AccessedTrainingRunDTO::getTitle)); - } else if (sortByTitle.equals("desc")) { + } else if (sortByTitle.equals(Sort.DESC)) { runs.sort(Comparator.comparing(AccessedTrainingRunDTO::getTitle).reversed()); - } } } return runs; @@ -410,30 +405,12 @@ public class TrainingRunFacade { } private AbstractPhaseDTO getCorrectAbstractPhaseDTO(AbstractPhase abstractPhase) { - AbstractPhaseDTO abstractPhaseDTO; if (abstractPhase instanceof QuestionnairePhase) { - QuestionnairePhase questionnairePhase = (QuestionnairePhase) abstractPhase; - abstractPhaseDTO = phaseMapper.mapToDTO(questionnairePhase); - abstractPhaseDTO.setPhaseType(PhaseType.QUESTIONNAIRE); - deleteInfoAboutCorrectnessFromQuestions((QuestionnairePhaseDTO) abstractPhaseDTO); + return phaseMapper.mapToQuestionnairePhaseViewDTO((QuestionnairePhase) abstractPhase); } else if (abstractPhase instanceof TrainingPhase) { - TrainingPhase trainingPhase = (TrainingPhase) abstractPhase; - abstractPhaseDTO = phaseMapper.mapToDTO(trainingPhase); - //TODO change the DTO with one task and remove the correct answer - abstractPhaseDTO.setPhaseType(PhaseType.TRAINING); + return phaseMapper.mapToTrainingPhaseViewDTO((TrainingPhase) abstractPhase); } else { - InfoPhase infoPhase = (InfoPhase) abstractPhase; - abstractPhaseDTO = phaseMapper.mapToDTO(infoPhase); - abstractPhaseDTO.setPhaseType(PhaseType.INFO); - } - return abstractPhaseDTO; - } - - private void deleteInfoAboutCorrectnessFromQuestions(QuestionnairePhaseDTO questionnairePhaseDTO) { - for (QuestionDTO questionDTO : questionnairePhaseDTO.getQuestions()) { - for (QuestionChoiceDTO questionChoiceDTO : questionDTO.getChoices()) { - questionChoiceDTO.setCorrect(null); - } + return phaseMapper.mapToDTO((InfoPhase) abstractPhase); } } } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/PhaseMapper.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/PhaseMapper.java index a6ba067b6cf6ee076a5e6bb5275ca2588104a6ee..3d5c9fd70f08851924013c10b540031952057dc0 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/PhaseMapper.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/PhaseMapper.java @@ -20,9 +20,11 @@ import cz.muni.ics.kypo.training.adaptive.dto.imports.phases.training.TrainingPh import cz.muni.ics.kypo.training.adaptive.dto.info.InfoPhaseDTO; import cz.muni.ics.kypo.training.adaptive.dto.info.InfoPhaseUpdateDTO; import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionnairePhaseDTO; +import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.view.QuestionnairePhaseViewDTO; import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionnaireUpdateDTO; import cz.muni.ics.kypo.training.adaptive.dto.training.TrainingPhaseDTO; import cz.muni.ics.kypo.training.adaptive.dto.training.TrainingPhaseUpdateDTO; +import cz.muni.ics.kypo.training.adaptive.dto.training.view.TrainingPhaseViewDTO; import cz.muni.ics.kypo.training.adaptive.exceptions.InternalServerErrorException; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -70,6 +72,9 @@ public interface PhaseMapper extends ParentMapper { @Mapping(target = "phaseType", constant = "QUESTIONNAIRE") QuestionnairePhaseDTO mapToQuestionnairePhaseDTO(QuestionnairePhase entity); + @Mapping(target = "phaseType", constant = "QUESTIONNAIRE") + QuestionnairePhaseViewDTO mapToQuestionnairePhaseViewDTO(QuestionnairePhase entity); + @Mapping(target = "phaseRelations", source = "questionPhaseRelations") @Mapping(target = "phaseType", constant = "QUESTIONNAIRE") QuestionnairePhaseArchiveDTO mapToQuestionnairePhaseArchiveDTO(QuestionnairePhase entity); @@ -91,6 +96,9 @@ public interface PhaseMapper extends ParentMapper { @Mapping(target = "phaseType", constant = "TRAINING") TrainingPhaseDTO mapToTrainingPhaseDTO(TrainingPhase entity); + @Mapping(target = "phaseType", constant = "TRAINING") + TrainingPhaseViewDTO mapToTrainingPhaseViewDTO(TrainingPhase entity); + @Mapping(target = "phaseType", constant = "TRAINING") TrainingPhaseExportDTO mapToTrainingPhaseExportDTO(TrainingPhase entity); @@ -103,11 +111,11 @@ public interface PhaseMapper extends ParentMapper { default AbstractPhaseDTO mapToDTO(AbstractPhase entity) { AbstractPhaseDTO abstractPhaseDTO; if (entity instanceof TrainingPhase) { - abstractPhaseDTO = mapToTrainingPhaseDTO((TrainingPhase) entity); + abstractPhaseDTO = mapToTrainingPhaseViewDTO((TrainingPhase) entity); } else if (entity instanceof InfoPhase) { abstractPhaseDTO = mapToInfoPhaseDTO((InfoPhase) entity); } else if (entity instanceof QuestionnairePhase) { - abstractPhaseDTO = mapToQuestionnairePhaseDTO((QuestionnairePhase) entity); + abstractPhaseDTO = mapToQuestionnairePhaseViewDTO((QuestionnairePhase) entity); } else { throw new InternalServerErrorException("Phase with id: " + entity.getId() + " in given training definition with id: " + entity.getTrainingDefinition().getId() + " is not instance of questionnaire, training or info phase."); diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/QuestionMapper.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/QuestionMapper.java index eb6db79a91b3166255b1e1b96d066fd8890f6871..e5a7d4f8f1b7d7c9d778173e98eabdb7bf46c511 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/QuestionMapper.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/QuestionMapper.java @@ -10,6 +10,8 @@ import cz.muni.ics.kypo.training.adaptive.dto.imports.phases.questionnaire.Quest import cz.muni.ics.kypo.training.adaptive.dto.imports.phases.questionnaire.QuestionImportDTO; import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionChoiceDTO; import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.QuestionDTO; +import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.view.QuestionChoiceViewDTO; +import cz.muni.ics.kypo.training.adaptive.dto.questionnaire.view.QuestionViewDTO; import org.mapstruct.Mapper; import org.mapstruct.ReportingPolicy; @@ -34,6 +36,8 @@ public interface QuestionMapper extends ParentMapper { QuestionDTO mapToQuestionDTO(Question entity); + QuestionViewDTO mapToQuestionViewDTO(Question entity); + List<Question> mapToList(Collection<QuestionDTO> dtos); List<QuestionDTO> mapToListDTO(Collection<Question> entities); @@ -53,6 +57,8 @@ public interface QuestionMapper extends ParentMapper { QuestionChoiceDTO mapToQuestionDTO(QuestionChoice entity); + QuestionChoiceViewDTO mapToQuestionViewDTO(QuestionChoice entity); + List<QuestionChoice> mapChoicesToList(Collection<QuestionChoiceDTO> dtos); List<QuestionDTO> mapToChoicesListDTO(Collection<QuestionChoice> entities); diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/TaskMapper.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/TaskMapper.java index 96aa29d2e153f0faaf3355d65911bda27386cb8b..39ecd1f26bbbcf8a83aac3f9c15da98cb6386cfa 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/TaskMapper.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/mapping/TaskMapper.java @@ -7,6 +7,7 @@ import cz.muni.ics.kypo.training.adaptive.dto.imports.phases.training.TaskImport import cz.muni.ics.kypo.training.adaptive.dto.training.TaskCopyDTO; import cz.muni.ics.kypo.training.adaptive.dto.training.TaskDTO; import cz.muni.ics.kypo.training.adaptive.dto.training.TaskUpdateDTO; +import cz.muni.ics.kypo.training.adaptive.dto.training.view.TaskViewDTO; import org.mapstruct.Mapper; import org.mapstruct.ReportingPolicy; @@ -34,6 +35,8 @@ public interface TaskMapper extends ParentMapper { TaskDTO mapToTaskDTO(Task entity); + TaskViewDTO mapToTaskViewDTO(Task entity); + List<Task> mapToList(Collection<TaskDTO> dtos); List<TaskDTO> mapToListDTO(Collection<Task> entities); diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/AdaptiveQuestionsFulfillmentRepository.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/AdaptiveQuestionsFulfillmentRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..418fde2f3d0edc1c17f2e65262c2c547ef065336 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/AdaptiveQuestionsFulfillmentRepository.java @@ -0,0 +1,10 @@ +package cz.muni.ics.kypo.training.adaptive.repository; + +import cz.muni.ics.kypo.training.adaptive.domain.phase.questions.TrainingPhaseQuestionsFulfillment; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; +import org.springframework.stereotype.Repository; + +@Repository +public interface AdaptiveQuestionsFulfillmentRepository extends JpaRepository<TrainingPhaseQuestionsFulfillment, Long>, QuerydslPredicateExecutor<TrainingPhaseQuestionsFulfillment> { +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionAnswerRepository.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionAnswerRepository.java index 620e628e9b6b1d8e8eadc3309fa74c526c37c212..b515abd974b073597df506fc34f2e47f10012b7a 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionAnswerRepository.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionAnswerRepository.java @@ -2,7 +2,6 @@ package cz.muni.ics.kypo.training.adaptive.repository; import cz.muni.ics.kypo.training.adaptive.domain.phase.questions.QuestionAnswer; import cz.muni.ics.kypo.training.adaptive.domain.phase.questions.QuestionAnswerId; -import cz.muni.ics.kypo.training.adaptive.domain.phase.questions.QuestionPhaseResult; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.stereotype.Repository; diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionPhaseResultRepository.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionsPhaseRelationResultRepository.java similarity index 60% rename from src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionPhaseResultRepository.java rename to src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionsPhaseRelationResultRepository.java index d8d5851e77c37a363ca2903c5ed43fc6fae8f35e..4a757fcf2e0250fec0955f766bbf843c910a6bd8 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionPhaseResultRepository.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/QuestionsPhaseRelationResultRepository.java @@ -1,10 +1,10 @@ package cz.muni.ics.kypo.training.adaptive.repository; -import cz.muni.ics.kypo.training.adaptive.domain.phase.questions.QuestionPhaseResult; +import cz.muni.ics.kypo.training.adaptive.domain.phase.questions.QuestionsPhaseRelationResult; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.stereotype.Repository; @Repository -public interface QuestionPhaseResultRepository extends JpaRepository<QuestionPhaseResult, Long>, QuerydslPredicateExecutor<QuestionPhaseResult> { +public interface QuestionsPhaseRelationResultRepository extends JpaRepository<QuestionsPhaseRelationResult, Long>, QuerydslPredicateExecutor<QuestionsPhaseRelationResult> { } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/QuestionnaireEvaluationService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/QuestionnaireEvaluationService.java index 6bdbd666605eb32e54382c5bf617c68ce5c6ae2d..e7b80b292957a0c1aa5e3c72582dec67167e3555 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/QuestionnaireEvaluationService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/QuestionnaireEvaluationService.java @@ -1,6 +1,7 @@ package cz.muni.ics.kypo.training.adaptive.service; import cz.muni.ics.kypo.training.adaptive.domain.phase.QuestionnairePhase; +import cz.muni.ics.kypo.training.adaptive.domain.phase.TrainingPhase; import cz.muni.ics.kypo.training.adaptive.domain.phase.questions.*; import cz.muni.ics.kypo.training.adaptive.domain.training.TrainingRun; import cz.muni.ics.kypo.training.adaptive.enums.QuestionnaireType; @@ -8,8 +9,9 @@ import cz.muni.ics.kypo.training.adaptive.exceptions.BadRequestException; import cz.muni.ics.kypo.training.adaptive.exceptions.EntityConflictException; import cz.muni.ics.kypo.training.adaptive.exceptions.EntityErrorDetail; import cz.muni.ics.kypo.training.adaptive.exceptions.EntityNotFoundException; +import cz.muni.ics.kypo.training.adaptive.repository.AdaptiveQuestionsFulfillmentRepository; import cz.muni.ics.kypo.training.adaptive.repository.QuestionAnswerRepository; -import cz.muni.ics.kypo.training.adaptive.repository.QuestionPhaseResultRepository; +import cz.muni.ics.kypo.training.adaptive.repository.QuestionsPhaseRelationResultRepository; import cz.muni.ics.kypo.training.adaptive.repository.phases.QuestionPhaseRelationRepository; import cz.muni.ics.kypo.training.adaptive.repository.phases.QuestionRepository; import cz.muni.ics.kypo.training.adaptive.repository.training.TrainingRunRepository; @@ -31,7 +33,8 @@ public class QuestionnaireEvaluationService { private final QuestionRepository questionRepository; private final QuestionAnswerRepository questionAnswerRepository; private final QuestionPhaseRelationRepository questionPhaseRelationRepository; - private final QuestionPhaseResultRepository questionPhaseResultRepository; + private final QuestionsPhaseRelationResultRepository questionsPhaseRelationResultRepository; + private final AdaptiveQuestionsFulfillmentRepository adaptiveQuestionsFulfillmentRepository; private final TrainingRunRepository trainingRunRepository; private final AuditEventsService auditEventsService; @@ -39,13 +42,15 @@ public class QuestionnaireEvaluationService { public QuestionnaireEvaluationService(QuestionRepository questionRepository, QuestionAnswerRepository questionAnswerRepository, QuestionPhaseRelationRepository questionPhaseRelationRepository, - QuestionPhaseResultRepository questionPhaseResultRepository, + QuestionsPhaseRelationResultRepository questionsPhaseRelationResultRepository, + AdaptiveQuestionsFulfillmentRepository adaptiveQuestionsFulfillmentRepository, TrainingRunRepository trainingRunRepository, AuditEventsService auditEventsService) { this.questionRepository = questionRepository; this.questionAnswerRepository = questionAnswerRepository; this.questionPhaseRelationRepository = questionPhaseRelationRepository; - this.questionPhaseResultRepository = questionPhaseResultRepository; + this.questionsPhaseRelationResultRepository = questionsPhaseRelationResultRepository; + this.adaptiveQuestionsFulfillmentRepository = adaptiveQuestionsFulfillmentRepository; this.trainingRunRepository = trainingRunRepository; this.auditEventsService = auditEventsService; } @@ -53,25 +58,25 @@ public class QuestionnaireEvaluationService { /** * Evaluate and store answers to questionnaire. * - * @param trainingRunId id of training run to answer the questionnaire. + * @param trainingRunId id of training run to answer the questionnaire. * @param questionnairePhaseAnswers answers to questionnaire to be evaluated. Map of entries (Key = question ID, Value = answer). * @throws EntityNotFoundException training run is not found. */ - public List<QuestionAnswer> saveAndEvaluateAnswersToQuestionnaire(Long trainingRunId, Map<Long, String> questionnairePhaseAnswers) { + public List<QuestionAnswer> saveAndEvaluateAnswersToQuestionnaire(Long trainingRunId, Map<Long, Set<String>> questionnairePhaseAnswers) { TrainingRun trainingRun = this.findByIdWithPhase(trainingRunId); this.checkIfCanBeEvaluated(trainingRun); List<QuestionAnswer> storedQuestionsAnswers = new ArrayList<>(); - for (Map.Entry<Long, String> questionAnswer : questionnairePhaseAnswers.entrySet()) { + for (Map.Entry<Long, Set<String>> questionAnswers : questionnairePhaseAnswers.entrySet()) { Long questionnaireId = trainingRun.getCurrentPhase().getId(); - storedQuestionsAnswers.add(saveQuestionAnswer(questionAnswer.getKey(), questionAnswer.getValue(), questionnaireId, trainingRun)); + storedQuestionsAnswers.add(saveQuestionAnswer(questionAnswers.getKey(), questionAnswers.getValue(), questionnaireId, trainingRun)); } if (((QuestionnairePhase) trainingRun.getCurrentPhase()).getQuestionnaireType() == QuestionnaireType.ADAPTIVE) { - this.evaluateAnswersToQuestionnaire(trainingRun, storedQuestionsAnswers); + this.evaluateAnswersToAdaptiveQuestionnaire(trainingRun, storedQuestionsAnswers); } auditEventsService.auditPhaseCompletedAction(trainingRun); auditEventsService.auditQuestionnaireAnswersAction(trainingRun, storedQuestionsAnswers.stream() - .collect(Collectors.toMap(questionAnswer -> questionAnswer.getQuestion().getText(), QuestionAnswer::getAnswer)) + .collect(Collectors.toMap(questionAnswer -> questionAnswer.getQuestion().getText(), QuestionAnswer::getAnswers)) .toString()); trainingRun.setPhaseAnswered(true); return storedQuestionsAnswers; @@ -86,66 +91,89 @@ public class QuestionnaireEvaluationService { "Current phase of the training run has been already answered.")); } - private QuestionAnswer saveQuestionAnswer(Long questionId, String answer, Long questionnaireId, TrainingRun trainingRun) { + private QuestionAnswer saveQuestionAnswer(Long questionId, Set<String> answers, Long questionnaireId, TrainingRun trainingRun) { Question question = this.findQuestionByIdAndQuestionnairePhaseId(questionId, questionnaireId); QuestionAnswer questionAnswer = new QuestionAnswer(question, trainingRun); - questionAnswer.setAnswer(answer); - + questionAnswer.setAnswers(answers); return questionAnswerRepository.save(questionAnswer); } - private void evaluateAnswersToQuestionnaire(TrainingRun trainingRun, List<QuestionAnswer> answers) { - if (CollectionUtils.isEmpty(answers)) { + private void evaluateAnswersToAdaptiveQuestionnaire(TrainingRun trainingRun, List<QuestionAnswer> questionAnswers) { + if (CollectionUtils.isEmpty(questionAnswers)) { return; } - - Set<Long> questionIdList = answers.stream() + Set<Long> questionIdList = questionAnswers.stream() .map(QuestionAnswer::getQuestionAnswerId) .map(QuestionAnswerId::getQuestionId) .collect(Collectors.toSet()); - List<QuestionPhaseRelation> questionPhaseRelations = questionPhaseRelationRepository.findAllByQuestionIdList(questionIdList); + Map<Long, Boolean> trainingPhaseQuestionsFulfilledMap = new HashMap<>(); + Map<Long, TrainingPhase> trainingPhasesMap = new HashMap<>(); + for (QuestionPhaseRelation questionPhaseRelation : questionPhaseRelations) { - int numberOfCorrectAnswers = 0; if (CollectionUtils.isEmpty(questionPhaseRelation.getQuestions())) { LOG.warn("No questions found for question phase relation {}", questionPhaseRelation.getId()); continue; } + TrainingPhase relatedTrainingPhase = questionPhaseRelation.getRelatedTrainingPhase(); + trainingPhasesMap.putIfAbsent(relatedTrainingPhase.getId(), relatedTrainingPhase); - for (Question question : questionPhaseRelation.getQuestions()) { - Optional<QuestionAnswer> correspondingAnswer = findCorrespondingAnswer(question.getId(), answers); - if (correspondingAnswer.isPresent()) { - String answer = correspondingAnswer.get().getAnswer(); - Optional<QuestionChoice> correspondingQuestionChoice = findCorrespondingQuestionChoice(answer, question.getChoices()); - if (correspondingQuestionChoice.isPresent() && correspondingQuestionChoice.get().isCorrect()) { - numberOfCorrectAnswers++; - } - } else { - LOG.debug("No answer found for question {}. It is assumed as a wrong answer", question.getId()); - } - } + double achievedResult = evaluateQuestionPhaseRelation(questionPhaseRelation, questionAnswers); + boolean trainingPhaseQuestionsFulfilled = trainingPhaseQuestionsFulfilledMap.getOrDefault(relatedTrainingPhase.getId(), true); + trainingPhaseQuestionsFulfilledMap.put(questionPhaseRelation.getRelatedTrainingPhase().getId(), trainingPhaseQuestionsFulfilled && questionPhaseRelation.getSuccessRate() < (achievedResult * 100)); + storeQuestionsPhaseRelationResult(questionPhaseRelation, trainingRun, achievedResult); + + } + storeTrainingPhaseQuestionsFulfillment(trainingRun, trainingPhaseQuestionsFulfilledMap.entrySet(), trainingPhasesMap); + } - int achievedResult = numberOfCorrectAnswers * 100 / questionPhaseRelation.getQuestions().size(); + private double evaluateQuestionPhaseRelation(QuestionPhaseRelation questionPhaseRelation, List<QuestionAnswer> questionAnswers) { + double numberOfCorrectlyAnsweredQuestions = 0; + for (Question question : questionPhaseRelation.getQuestions()) { + Optional<QuestionAnswer> correspondingAnswer = findCorrespondingAnswer(question.getId(), questionAnswers); + if (correspondingAnswer.isPresent() && checkCorrectnessOfAnswersToQuestion(correspondingAnswer.get().getAnswers(), question)) { + numberOfCorrectlyAnsweredQuestions++; + } else { + LOG.debug("No answer found for question {}. It is assumed as a wrong answer", question.getId()); + } + } + return numberOfCorrectlyAnsweredQuestions / questionPhaseRelation.getQuestions().size(); - QuestionPhaseResult questionPhaseResult = new QuestionPhaseResult(); - questionPhaseResult.setAchievedResult(achievedResult); - questionPhaseResult.setQuestionPhaseRelation(questionPhaseRelation); - questionPhaseResult.setTrainingRun(trainingRun); + } - questionPhaseResultRepository.save(questionPhaseResult); + private void storeTrainingPhaseQuestionsFulfillment(TrainingRun trainingRun, + Set<Map.Entry<Long, Boolean>> trainingPhasesQuestionsFulfillmentMap, + Map<Long, TrainingPhase> trainingPhaseMap) { + for (Map.Entry<Long, Boolean> questionsFulfillment : trainingPhasesQuestionsFulfillmentMap) { + TrainingPhaseQuestionsFulfillment trainingPhaseQuestionsFulfillment = new TrainingPhaseQuestionsFulfillment(); + trainingPhaseQuestionsFulfillment.setTrainingRun(trainingRun); + trainingPhaseQuestionsFulfillment.setTrainingPhase(trainingPhaseMap.get(questionsFulfillment.getKey())); + trainingPhaseQuestionsFulfillment.setFulfilled(questionsFulfillment.getValue()); + this.adaptiveQuestionsFulfillmentRepository.save(trainingPhaseQuestionsFulfillment); } } + private void storeQuestionsPhaseRelationResult(QuestionPhaseRelation questionPhaseRelation, + TrainingRun trainingRun, + double achievedResult) { + QuestionsPhaseRelationResult questionPhaseResult = new QuestionsPhaseRelationResult(); + questionPhaseResult.setAchievedResult(achievedResult); + questionPhaseResult.setQuestionPhaseRelation(questionPhaseRelation); + questionPhaseResult.setTrainingRun(trainingRun); + questionsPhaseRelationResultRepository.save(questionPhaseResult); + } + private Optional<QuestionAnswer> findCorrespondingAnswer(Long questionId, List<QuestionAnswer> answers) { return answers.stream() .filter(a -> Objects.equals(questionId, a.getQuestionAnswerId().getQuestionId())) .findFirst(); } - private Optional<QuestionChoice> findCorrespondingQuestionChoice(String answer, List<QuestionChoice> questionChoices) { - return questionChoices.stream() - .filter(q -> Objects.equals(answer, q.getText())) - .findFirst(); + private boolean checkCorrectnessOfAnswersToQuestion(Set<String> answers, Question question) { + int numberOfCorrectAnswers = (int) question.getChoices().stream() + .filter(questionChoice -> answers.contains(questionChoice.getText()) && questionChoice.isCorrect()) + .count(); + return numberOfCorrectAnswers == answers.size(); } private TrainingRun findByIdWithPhase(Long runId) { diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java index 13ffba22d9749b85cc7ac8498b945221a55c6498..fd8908fd2a289e08e90addb305fa80af730f1632 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java @@ -193,6 +193,7 @@ public class TrainingRunService { auditEventsService.auditPhaseCompletedAction(trainingRun); } if (nextPhase instanceof TrainingPhase) { + //TODO call the smart assistant trainingRun.setCurrentTask(((TrainingPhase) nextPhase).getTasks().get(0)); } else { trainingRun.setCurrentTask(null); @@ -251,6 +252,7 @@ public class TrainingRunService { AbstractPhase initialPhase = findFirstPhaseForTrainingRun(trainingInstance.getTrainingDefinition().getId()); TrainingRun trainingRun = getNewTrainingRun(initialPhase, trainingInstance, LocalDateTime.now(Clock.systemUTC()), trainingInstance.getEndTime(), participantRefId); if (initialPhase instanceof TrainingPhase) { + //TODO call smart assistant trainingRun.setCurrentTask(((TrainingPhase) initialPhase).getTasks().get(0)); } return trainingRunRepository.save(trainingRun); @@ -499,18 +501,4 @@ public class TrainingRunService { trAcquisitionLockRepository.deleteByParticipantRefIdAndTrainingInstanceId(trainingRun.getParticipantRef().getUserRefId(), trainingRun.getTrainingInstance().getId()); trainingRunRepository.save(trainingRun); } - - - public void evaluateResponsesToQuestionnaire(Long trainingRunId, String responsesAsString) { - TrainingRun trainingRun = findByIdWithPhase(trainingRunId); - if (!(trainingRun.getCurrentPhase() instanceof QuestionnairePhase)) { - throw new BadRequestException("Current phase is not questionnaire phase and cannot be evaluated."); - } - if (trainingRun.isPhaseAnswered()) - throw new EntityConflictException(new EntityErrorDetail(TrainingRun.class, "id", trainingRunId.getClass(), trainingRunId, - "Current phase of the training run has been already answered.")); - //TODO complete the evaluation - auditEventsService.auditQuestionnaireAnswersAction(trainingRun, responsesAsString); - auditEventsService.auditPhaseCompletedAction(trainingRun); - } } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/utils/Sort.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/utils/Sort.java new file mode 100644 index 0000000000000000000000000000000000000000..bd7f8da2b9fdc985d4541c4afb218f2fff81ef1c --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/utils/Sort.java @@ -0,0 +1,6 @@ +package cz.muni.ics.kypo.training.adaptive.utils; + +public abstract class Sort { + public static final String ASC = "asc"; + public static final String DESC = "desc"; +} diff --git a/src/main/resources/db/migration/V1__db_adaptive_trainings_schema.sql b/src/main/resources/db/migration/V1__db_adaptive_trainings_schema.sql index 34d3d1f62c06e1b7c0fed65f804e8c7eb695ec29..154f5e9113f8f84bd863e60a2f1982a21d37e1f9 100644 --- a/src/main/resources/db/migration/V1__db_adaptive_trainings_schema.sql +++ b/src/main/resources/db/migration/V1__db_adaptive_trainings_schema.sql @@ -175,22 +175,40 @@ create table question_phase_relation_question ( create table question_answer ( question_id int8 not null, training_run_id int8 not null, - answer varchar(255) not null, primary key (question_id, training_run_id), foreign key (question_id) references question, foreign key (training_run_id) references training_run, unique (question_id, training_run_id) ); -create table question_phase_result ( - question_phase_result_id bigserial not null, +create table question_answers ( + question_id int8 not null, + training_run_id int8 not null, + answer varchar(255) not null, + primary key (question_id, training_run_id), + foreign key (question_id, training_run_id) references question_answer, + unique (question_id, training_run_id) +); + + +create table questions_phase_relation_result ( + questions_phase_relation_result_id bigserial not null, training_run_id int8 not null, question_phase_relation_id int8 not null, - achieved_result int4 not null, - primary key (question_phase_result_id), + achieved_result double precision not null, + primary key (questions_phase_relation_result_id), foreign key (question_phase_relation_id) references question_phase_relation ); +create table adaptive_questions_fulfillment ( + adaptive_questions_fulfillment_id bigserial not null, + training_run_id int8 not null, + training_phase_id int8 not null, + fulfilled boolean not null, + primary key (adaptive_questions_fulfillment_id), + foreign key (training_phase_id) references training_phase +); + -- ACCESS TOKEN create table access_token ( access_token_id bigserial not null, diff --git a/src/main/resources/db/migration/V2__db_adaptive_trainings_sequences.sql b/src/main/resources/db/migration/V2__db_adaptive_trainings_sequences.sql index 74badbf022f80b566c539315bdb72d1aa5230be9..d38dd26a0b02004792e2992aceaf7b85973d02be 100644 --- a/src/main/resources/db/migration/V2__db_adaptive_trainings_sequences.sql +++ b/src/main/resources/db/migration/V2__db_adaptive_trainings_sequences.sql @@ -4,7 +4,8 @@ CREATE SEQUENCE question_seq AS bigint INCREMENT 50 MINVALUE 1; CREATE SEQUENCE question_choice_seq AS bigint INCREMENT 50 MINVALUE 1; CREATE SEQUENCE question_phase_seq AS bigint INCREMENT 50 MINVALUE 1; CREATE SEQUENCE decision_matrix_row_seq AS bigint INCREMENT 50 MINVALUE 1; -CREATE SEQUENCE question_phase_result_seq AS bigint INCREMENT 50 MINVALUE 1; +CREATE SEQUENCE adaptive_questions_fulfillment_seq AS bigint INCREMENT 50 MINVALUE 1; +CREATE SEQUENCE questions_phase_relation_result_seq AS bigint INCREMENT 50 MINVALUE 1; CREATE SEQUENCE training_definition_seq AS bigint INCREMENT 50 MINVALUE 1; CREATE SEQUENCE training_instance_seq AS bigint INCREMENT 50 MINVALUE 1; CREATE SEQUENCE training_run_seq AS bigint INCREMENT 50 MINVALUE 1;