Skip to content

Commit cc44944

Browse files
authored
Tutor exam dashboard for the assessment of exams (#1727)
1 parent 7e0c36c commit cc44944

26 files changed

+662
-196
lines changed

src/main/java/de/tum/in/www1/artemis/domain/Course.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package de.tum.in.www1.artemis.domain;
22

33
import static de.tum.in.www1.artemis.config.Constants.ARTEMIS_GROUP_DEFAULT_PREFIX;
4-
import static de.tum.in.www1.artemis.domain.enumeration.AssessmentType.AUTOMATIC;
54

65
import java.io.Serializable;
76
import java.time.ZonedDateTime;
87
import java.util.HashSet;
98
import java.util.Objects;
109
import java.util.Set;
11-
import java.util.stream.Collectors;
1210

1311
import javax.persistence.CascadeType;
1412
import javax.persistence.Column;
@@ -34,7 +32,6 @@
3432

3533
import de.tum.in.www1.artemis.config.Constants;
3634
import de.tum.in.www1.artemis.domain.exam.Exam;
37-
import de.tum.in.www1.artemis.domain.modeling.ModelingExercise;
3835
import de.tum.in.www1.artemis.domain.view.QuizView;
3936
import de.tum.in.www1.artemis.service.FilePathService;
4037
import de.tum.in.www1.artemis.service.FileService;
@@ -580,12 +577,6 @@ public String toString() {
580577
+ ", presentationScore='" + getPresentationScore() + "}";
581578
}
582579

583-
@JsonIgnore
584-
public Set<Exercise> getInterestingExercisesForAssessmentDashboards() {
585-
return getExercises().stream().filter(exercise -> exercise instanceof TextExercise || exercise instanceof ModelingExercise || exercise instanceof FileUploadExercise
586-
|| (exercise instanceof ProgrammingExercise && exercise.getAssessmentType() != AUTOMATIC)).collect(Collectors.toSet());
587-
}
588-
589580
public void setNumberOfInstructors(Long numberOfInstructors) {
590581
this.numberOfInstructorsTransient = numberOfInstructors;
591582
}

src/main/java/de/tum/in/www1/artemis/domain/Exercise.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ public abstract class Exercise implements Serializable {
156156

157157
@ManyToOne
158158
@JsonView(QuizView.Before.class)
159-
@JsonIgnoreProperties(value = "exercises")
160159
private ExerciseGroup exerciseGroup;
161160

162161
@OneToMany(mappedBy = "exercise", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)

src/main/java/de/tum/in/www1/artemis/domain/exam/Exam.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public class Exam implements Serializable {
8383
@OneToMany(mappedBy = "exam", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
8484
@OrderColumn(name = "exercise_group_order")
8585
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
86-
@JsonIgnoreProperties("exam")
86+
@JsonIgnoreProperties(value = "exam", allowSetters = true)
8787
private List<ExerciseGroup> exerciseGroups = new ArrayList<>();
8888

8989
// TODO: add a big fat warning in case instructor delete exams where student exams already exist
@@ -253,12 +253,12 @@ public void setRegisteredUsers(Set<User> registeredUsers) {
253253
this.registeredUsers = registeredUsers;
254254
}
255255

256-
public Exam addUser(User user) {
256+
public Exam addRegisteredUser(User user) {
257257
this.registeredUsers.add(user);
258258
return this;
259259
}
260260

261-
public Exam removeUser(User user) {
261+
public Exam removeRegisteredUser(User user) {
262262
this.registeredUsers.remove(user);
263263
return this;
264264
}

src/main/java/de/tum/in/www1/artemis/domain/exam/ExerciseGroup.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public class ExerciseGroup implements Serializable {
4949

5050
@OneToMany(mappedBy = "exerciseGroup", fetch = FetchType.LAZY)
5151
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
52-
@JsonIgnoreProperties("exerciseGroup")
52+
@JsonIgnoreProperties(value = "exerciseGroup", allowSetters = true)
5353
private Set<Exercise> exercises = new HashSet<>();
5454

5555
public Long getId() {

src/main/java/de/tum/in/www1/artemis/repository/CourseRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,7 @@ public interface CourseRepository extends JpaRepository<Course, Long> {
4949
List<Course> findAllCurrentlyActiveAndNotOnlineAndEnabled(@Param("now") ZonedDateTime now);
5050

5151
List<Course> findAllByShortName(String shortName);
52+
53+
Optional<Course> findById(long courseId);
54+
5255
}

src/main/java/de/tum/in/www1/artemis/service/CourseService.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package de.tum.in.www1.artemis.service;
22

3+
import static de.tum.in.www1.artemis.domain.enumeration.AssessmentType.AUTOMATIC;
4+
35
import java.time.ZonedDateTime;
46
import java.util.List;
7+
import java.util.Set;
58
import java.util.stream.Collectors;
69

710
import javax.validation.constraints.NotNull;
@@ -11,10 +14,9 @@
1114
import org.springframework.beans.factory.annotation.Autowired;
1215
import org.springframework.stereotype.Service;
1316

14-
import de.tum.in.www1.artemis.domain.Course;
15-
import de.tum.in.www1.artemis.domain.Exercise;
16-
import de.tum.in.www1.artemis.domain.User;
17+
import de.tum.in.www1.artemis.domain.*;
1718
import de.tum.in.www1.artemis.domain.exam.ExerciseGroup;
19+
import de.tum.in.www1.artemis.domain.modeling.ModelingExercise;
1820
import de.tum.in.www1.artemis.repository.CourseRepository;
1921
import de.tum.in.www1.artemis.repository.UserRepository;
2022
import de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException;
@@ -225,4 +227,14 @@ public Course retrieveCourseOverExerciseGroupOrCourseId(Exercise exercise) {
225227
return findOne(exercise.getCourseViaExerciseGroupOrCourseMember().getId());
226228
}
227229
}
230+
231+
/**
232+
* filters the passed exercises for the relevant ones that need to be manually assessed. This excludes quizzes and automatic programming exercises
233+
* @param exercises all exercises (e.g. of a course or exercise group) that should be filtered
234+
* @return the filtered and relevant exercises for manual assessment
235+
*/
236+
public Set<Exercise> getInterestingExercisesForAssessmentDashboards(Set<Exercise> exercises) {
237+
return exercises.stream().filter(exercise -> exercise instanceof TextExercise || exercise instanceof ModelingExercise || exercise instanceof FileUploadExercise
238+
|| (exercise instanceof ProgrammingExercise && exercise.getAssessmentType() != AUTOMATIC)).collect(Collectors.toSet());
239+
}
228240
}

src/main/java/de/tum/in/www1/artemis/service/ExamService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ public List<StudentDTO> registerStudentsForExam(@PathVariable Long courseId, @Pa
358358
if (!student.getGroups().contains(course.getStudentGroupName())) {
359359
userService.addUserToGroup(student, course.getStudentGroupName());
360360
}
361-
exam.addUser(student);
361+
exam.addRegisteredUser(student);
362362
continue;
363363
}
364364
// 2) if we cannot find the student, we use the registration number and try to find the student in the (TUM) LDAP, create it in the Artemis DB and in a potential
@@ -368,7 +368,7 @@ public List<StudentDTO> registerStudentsForExam(@PathVariable Long courseId, @Pa
368368
var student = optionalStudent.get();
369369
// the newly created student needs to get the rights to access the course, otherwise the student cannot access the exam (within the course)
370370
userService.addUserToGroup(student, course.getStudentGroupName());
371-
exam.addUser(student);
371+
exam.addRegisteredUser(student);
372372
continue;
373373
}
374374
// 3) if we cannot find the user in the (TUM) LDAP, we report this to the client
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package de.tum.in.www1.artemis.service;
2+
3+
import java.util.Collections;
4+
import java.util.HashSet;
5+
import java.util.List;
6+
import java.util.Set;
7+
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
import org.springframework.stereotype.Service;
11+
12+
import de.tum.in.www1.artemis.domain.ExampleSubmission;
13+
import de.tum.in.www1.artemis.domain.Exercise;
14+
import de.tum.in.www1.artemis.domain.ProgrammingExercise;
15+
import de.tum.in.www1.artemis.domain.enumeration.TutorParticipationStatus;
16+
import de.tum.in.www1.artemis.domain.participation.TutorParticipation;
17+
import de.tum.in.www1.artemis.repository.ExampleSubmissionRepository;
18+
import de.tum.in.www1.artemis.web.rest.dto.DueDateStat;
19+
20+
/**
21+
* Service Implementation for managing Tutor-Assessment-Dashboard.
22+
*/
23+
@Service
24+
public class TutorDashboardService {
25+
26+
private final Logger log = LoggerFactory.getLogger(ExamService.class);
27+
28+
private final ExerciseService exerciseService;
29+
30+
private final ProgrammingExerciseService programmingExerciseService;
31+
32+
private final SubmissionService submissionService;
33+
34+
private final ResultService resultService;
35+
36+
private final ExampleSubmissionRepository exampleSubmissionRepository;
37+
38+
public TutorDashboardService(ExerciseService exerciseService, ProgrammingExerciseService programmingExerciseService, SubmissionService submissionService,
39+
ResultService resultService, ExampleSubmissionRepository exampleSubmissionRepository) {
40+
this.exerciseService = exerciseService;
41+
this.programmingExerciseService = programmingExerciseService;
42+
this.submissionService = submissionService;
43+
this.resultService = resultService;
44+
this.exampleSubmissionRepository = exampleSubmissionRepository;
45+
}
46+
47+
/**
48+
* Prepares the exercises for the tutor dashboard by setting the tutor participations and statistics
49+
*
50+
* @param exercises exercises to be prepared for the tutor dashboard
51+
* @param tutorParticipations participations of the tutors
52+
*/
53+
public void prepareExercisesForTutorDashboard(Set<Exercise> exercises, List<TutorParticipation> tutorParticipations) {
54+
for (Exercise exercise : exercises) {
55+
56+
DueDateStat numberOfSubmissions;
57+
DueDateStat numberOfAssessments;
58+
59+
if (exercise instanceof ProgrammingExercise) {
60+
numberOfSubmissions = new DueDateStat(programmingExerciseService.countSubmissionsByExerciseIdSubmitted(exercise.getId()), 0L);
61+
numberOfAssessments = new DueDateStat(programmingExerciseService.countAssessmentsByExerciseIdSubmitted(exercise.getId()), 0L);
62+
}
63+
else {
64+
numberOfSubmissions = submissionService.countSubmissionsForExercise(exercise.getId());
65+
numberOfAssessments = resultService.countNumberOfFinishedAssessmentsForExercise(exercise.getId());
66+
}
67+
68+
exercise.setNumberOfSubmissions(numberOfSubmissions);
69+
exercise.setNumberOfAssessments(numberOfAssessments);
70+
71+
exerciseService.calculateNrOfOpenComplaints(exercise);
72+
73+
List<ExampleSubmission> exampleSubmissions = this.exampleSubmissionRepository.findAllByExerciseId(exercise.getId());
74+
// Do not provide example submissions without any assessment
75+
exampleSubmissions.removeIf(exampleSubmission -> exampleSubmission.getSubmission() == null || exampleSubmission.getSubmission().getResult() == null);
76+
exercise.setExampleSubmissions(new HashSet<>(exampleSubmissions));
77+
78+
TutorParticipation tutorParticipation = tutorParticipations.stream().filter(participation -> participation.getAssessedExercise().getId().equals(exercise.getId()))
79+
.findFirst().orElseGet(() -> {
80+
TutorParticipation emptyTutorParticipation = new TutorParticipation();
81+
emptyTutorParticipation.setStatus(TutorParticipationStatus.NOT_PARTICIPATED);
82+
return emptyTutorParticipation;
83+
});
84+
exercise.setTutorParticipations(Collections.singleton(tutorParticipation));
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)