Skip to content

Commit 3da75e7

Browse files
committed
Programming exercises: Send the correction round to the client
The assessment endpoints for text, file upload and programming answer with DTOs, and those never carried a correction round because the round used to be the position of the result in the submission's list. Now that the client matches on the round itself, it found no result for the round it asked for and the assessment editor stayed empty, which broke assessing an exam submission for those three types. Modeling was not affected because it answers with the entity. Also add a test for the serialized form: the DTOs omit empty values, and a zero being treated as empty would drop the first correction round while leaving the second one working.
1 parent 5570b78 commit 3da75e7

5 files changed

Lines changed: 75 additions & 25 deletions

File tree

src/main/java/de/tum/cit/aet/artemis/assessment/dto/ResultDTO.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
*/
2323
@JsonInclude(JsonInclude.Include.NON_EMPTY)
2424
public record ResultDTO(Long id, ZonedDateTime completionDate, Boolean successful, Double score, Boolean rated, SubmissionDTO submission, ParticipationDTO participation,
25-
List<FeedbackDTO> feedbacks, AssessmentType assessmentType, Boolean hasComplaint, Boolean exampleResult, UserNameDTO assessor, AssessmentNoteDTO assessmentNote)
26-
implements Serializable {
25+
List<FeedbackDTO> feedbacks, AssessmentType assessmentType, Integer correctionRound, Boolean hasComplaint, Boolean exampleResult, UserNameDTO assessor,
26+
AssessmentNoteDTO assessmentNote) implements Serializable {
2727

2828
/**
2929
* Converts a Result into a ResultDTO.
@@ -53,6 +53,6 @@ public static ResultDTO of(Result result) {
5353
}
5454
AssessmentNoteDTO assessmentNoteDTO = AssessmentNoteDTO.of(result.getAssessmentNote());
5555
return new ResultDTO(result.getId(), result.getCompletionDate(), result.isSuccessful(), result.getScore(), result.isRated(), submissionDTO, participationDTO, feedbackDTOs,
56-
result.getAssessmentType(), result.hasComplaint(), result.isExampleResult(), assessorDTO, assessmentNoteDTO);
56+
result.getAssessmentType(), result.getCorrectionRound(), result.hasComplaint(), result.isExampleResult(), assessorDTO, assessmentNoteDTO);
5757
}
5858
}

src/main/java/de/tum/cit/aet/artemis/exercise/service/ParticipationFilterService.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE;
44

55
import java.util.Comparator;
6-
import java.util.HashSet;
6+
import java.util.LinkedHashSet;
77
import java.util.Optional;
88
import java.util.Set;
99
import java.util.stream.Collectors;
@@ -95,7 +95,7 @@ public void filterParticipationForCourseDashboard(StudentParticipation participa
9595
latestResult.filterSensitiveInformation();
9696
}
9797
}
98-
submission.setResults(new HashSet<>(results));
98+
submission.setResults(new LinkedHashSet<>(results));
9999
}
100100
else {
101101
// A quiz that has not ended yet intentionally exposes neither its submission's answers nor its result (see
@@ -130,7 +130,7 @@ private Optional<Submission> getSanitizedSubmittedQuizSubmission(StudentParticip
130130
sanitizedSubmission.setId(submission.getId());
131131
sanitizedSubmission.setSubmitted(true);
132132
sanitizedSubmission.setSubmissionDate(submission.getSubmissionDate());
133-
sanitizedSubmission.setResults(new HashSet<>());
133+
sanitizedSubmission.setResults(new LinkedHashSet<>());
134134
return sanitizedSubmission;
135135
});
136136
}

src/main/java/de/tum/cit/aet/artemis/fileupload/dto/FileUploadResultDTO.java

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,25 @@
1919
/**
2020
* DTO representing a result / assessment of a file upload submission.
2121
*
22-
* @param id the ID of the result
23-
* @param completionDate the date and time when the assessment was completed
24-
* @param successful whether the result is considered successful
25-
* @param score the score achieved (in percent or points depending on context)
26-
* @param rated whether the result is rated (counts for the final score)
27-
* @param assessmentType the type of assessment (e.g. MANUAL, AUTOMATIC)
28-
* @param hasComplaint whether a complaint has been filed for this result
29-
* @param exampleResult whether this result belongs to an example submission
30-
* @param assessmentNote the assessment note associated with the result
31-
* @param assessor the tutor/instructor who assessed the submission
32-
* @param feedbacks the feedbacks generated for this result
33-
* @param submission the submission context if requested
22+
* @param id the ID of the result
23+
* @param completionDate the date and time when the assessment was completed
24+
* @param successful whether the result is considered successful
25+
* @param score the score achieved (in percent or points depending on context)
26+
* @param rated whether the result is rated (counts for the final score)
27+
* @param assessmentType the type of assessment (e.g. MANUAL, AUTOMATIC)
28+
* @param hasComplaint whether a complaint has been filed for this result
29+
* @param exampleResult whether this result belongs to an example submission
30+
* @param correctionRound which correction round the result belongs to
31+
* @param assessmentNote the assessment note associated with the result
32+
* @param assessor the tutor/instructor who assessed the submission
33+
* @param feedbacks the feedbacks generated for this result
34+
* @param submission the submission context if requested
3435
*/
3536
@JsonInclude(JsonInclude.Include.NON_EMPTY)
3637
public record FileUploadResultDTO(Long id, @Nullable ZonedDateTime completionDate, @Nullable Boolean successful, @Nullable Double score, boolean rated,
37-
@Nullable AssessmentType assessmentType, @Nullable Boolean hasComplaint, @Nullable Boolean exampleResult, @Nullable FileUploadAssessmentNoteDTO assessmentNote,
38-
@Nullable FileUploadUserDTO assessor, @Nullable List<FileUploadFeedbackDTO> feedbacks, @Nullable FileUploadSubmissionDTO submission) {
38+
@Nullable AssessmentType assessmentType, @Nullable Integer correctionRound, @Nullable Boolean hasComplaint, @Nullable Boolean exampleResult,
39+
@Nullable FileUploadAssessmentNoteDTO assessmentNote, @Nullable FileUploadUserDTO assessor, @Nullable List<FileUploadFeedbackDTO> feedbacks,
40+
@Nullable FileUploadSubmissionDTO submission) {
3941

4042
/**
4143
* Factory method to map a {@link Result} entity to a nested {@link FileUploadResultDTO} (without including submission loop).
@@ -86,6 +88,6 @@ public record FileUploadResultDTO(Long id, @Nullable ZonedDateTime completionDat
8688
}
8789

8890
return new FileUploadResultDTO(result.getId(), result.getCompletionDate(), result.isSuccessful(), result.getScore(), result.isRated(), result.getAssessmentType(),
89-
result.hasComplaint(), result.isExampleResult(), assessmentNoteDTO, assessorDTO, feedbackDTOs, submissionDTO);
91+
result.getCorrectionRound(), result.hasComplaint(), result.isExampleResult(), assessmentNoteDTO, assessorDTO, feedbackDTOs, submissionDTO);
9092
}
9193
}

src/main/java/de/tum/cit/aet/artemis/programming/dto/ResultDTO.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
// this would also simplify the logic in result.component.ts and and result.service.ts and make the experience more consistent among different clients (webapp, ios, android)
2727
@JsonInclude(JsonInclude.Include.NON_EMPTY)
2828
public record ResultDTO(Long id, ZonedDateTime completionDate, Boolean successful, Double score, Boolean rated, SubmissionDTO submission, ParticipationDTO participation,
29-
List<FeedbackDTO> feedbacks, AssessmentType assessmentType, Boolean hasComplaint, Boolean exampleResult, Integer testCaseCount, Integer passedTestCaseCount,
30-
Integer codeIssueCount) implements Serializable {
29+
List<FeedbackDTO> feedbacks, AssessmentType assessmentType, Integer correctionRound, Boolean hasComplaint, Boolean exampleResult, Integer testCaseCount,
30+
Integer passedTestCaseCount, Integer codeIssueCount) implements Serializable {
3131

3232
@JsonInclude(JsonInclude.Include.NON_EMPTY)
3333
public record FeedbackDTO(Long id, String text, String detailText, boolean hasLongFeedbackText, String reference, Double credits, Boolean positive, FeedbackType type,
@@ -68,7 +68,7 @@ public static ResultDTO of(Result result, Collection<Feedback> filteredFeedback)
6868
}
6969
var feedbackDTOs = filteredFeedback.stream().map(FeedbackDTO::of).toList();
7070
return new ResultDTO(result.getId(), result.getCompletionDate(), result.isSuccessful(), result.getScore(), result.isRated(), submissionDTO,
71-
ParticipationDTO.of(result.getSubmission().getParticipation()), feedbackDTOs, result.getAssessmentType(), result.hasComplaint(), result.isExampleResult(),
72-
result.getTestCaseCount(), result.getPassedTestCaseCount(), result.getCodeIssueCount());
71+
ParticipationDTO.of(result.getSubmission().getParticipation()), feedbackDTOs, result.getAssessmentType(), result.getCorrectionRound(), result.hasComplaint(),
72+
result.isExampleResult(), result.getTestCaseCount(), result.getPassedTestCaseCount(), result.getCodeIssueCount());
7373
}
7474
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package de.tum.cit.aet.artemis.assessment;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.time.ZonedDateTime;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
11+
12+
import de.tum.cit.aet.artemis.assessment.domain.AssessmentType;
13+
import de.tum.cit.aet.artemis.assessment.domain.Result;
14+
import de.tum.cit.aet.artemis.assessment.dto.ResultDTO;
15+
16+
class ResultDTOSerializationTest {
17+
18+
private final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
19+
20+
/**
21+
* The client matches a result to a correction round by this field, so it has to survive serialization. Round 0 is
22+
* the interesting case: the DTOs carry {@code @JsonInclude(NON_EMPTY)}, and a zero being treated as empty would
23+
* silently drop the first correction round.
24+
*/
25+
@Test
26+
void shouldSerializeCorrectionRoundZero() throws Exception {
27+
Result result = new Result();
28+
result.setId(1L);
29+
result.setAssessmentType(AssessmentType.MANUAL);
30+
result.setCompletionDate(ZonedDateTime.now());
31+
result.setCorrectionRound(0);
32+
33+
String json = objectMapper.writeValueAsString(ResultDTO.of(result));
34+
35+
assertThat(json).contains("\"correctionRound\":0");
36+
}
37+
38+
@Test
39+
void shouldOmitCorrectionRoundWhenAbsent() throws Exception {
40+
Result result = new Result();
41+
result.setId(1L);
42+
result.setAssessmentType(AssessmentType.AUTOMATIC);
43+
44+
String json = objectMapper.writeValueAsString(ResultDTO.of(result));
45+
46+
assertThat(json).doesNotContain("correctionRound");
47+
}
48+
}

0 commit comments

Comments
 (0)