use of de.tum.in.www1.artemis.domain.exam.StudentExam in project Artemis by ls1intum.
the class StudentExamAccessServiceTest method testExamIsLive.
@Test
@WithMockUser(username = "student1", roles = "USER")
public void testExamIsLive() {
// Exam is not visible.
Exam examNotStarted = database.addExam(course1, users.get(0), ZonedDateTime.now().plusHours(1), ZonedDateTime.now().plusHours(2), ZonedDateTime.now().plusHours(3));
assertThrows(AccessForbiddenException.class, () -> studentExamAccessService.checkCourseAndExamAccessElseThrow(course1.getId(), examNotStarted.getId(), users.get(0), false));
assertThrows(AccessForbiddenException.class, () -> studentExamAccessService.checkStudentExamAccessElseThrow(course1.getId(), examNotStarted.getId(), studentExam1.getId(), false));
assertThrows(AccessForbiddenException.class, () -> studentExamAccessService.checkStudentExamAccessElseThrow(course1.getId(), examNotStarted.getId(), studentExam1.getId(), users.get(0), false));
// Exam has ended. After exam has ended, it should still be retrievable by the students to see their participation
Exam examEnded = database.addExam(course1, users.get(0), ZonedDateTime.now().minusHours(4), ZonedDateTime.now().minusHours(3), ZonedDateTime.now().minusHours(1));
StudentExam studentExamEnded = database.addStudentExam(examEnded);
studentExamEnded.setUser(users.get(0));
studentExamRepository.save(studentExamEnded);
// does not throw
studentExamAccessService.checkCourseAndExamAccessElseThrow(course1.getId(), examEnded.getId(), users.get(0), false);
// does not throw
studentExamAccessService.checkStudentExamAccessElseThrow(course1.getId(), examEnded.getId(), studentExamEnded.getId(), false);
// does not throw
studentExamAccessService.checkStudentExamAccessElseThrow(course1.getId(), examEnded.getId(), studentExamEnded.getId(), users.get(0), false);
}
use of de.tum.in.www1.artemis.domain.exam.StudentExam in project ArTEMiS by ls1intum.
the class ExamResource method generateStudentExams.
/**
* POST /courses/:courseId/exams/:examId/generate-student-exams : Generates the student exams randomly based on the exam configuration and the exercise groups
*
* @param courseId the id of the course
* @param examId the id of the exam
* @return the list of student exams with their corresponding users
*/
@PostMapping(value = "/courses/{courseId}/exams/{examId}/generate-student-exams")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<List<StudentExam>> generateStudentExams(@PathVariable Long courseId, @PathVariable Long examId) {
long start = System.nanoTime();
log.info("REST request to generate student exams for exam {}", examId);
final Exam exam = examRepository.findByIdWithRegisteredUsersExerciseGroupsAndExercisesElseThrow(examId);
examAccessService.checkCourseAndExamAccessForInstructorElseThrow(courseId, exam);
// Validate settings of the exam
examService.validateForStudentExamGeneration(exam);
examService.combineTemplateCommitsOfAllProgrammingExercisesInExam(exam);
List<StudentExam> studentExams = studentExamRepository.generateStudentExams(exam);
// we need to break a cycle for the serialization
for (StudentExam studentExam : studentExams) {
studentExam.getExam().setRegisteredUsers(null);
studentExam.getExam().setExerciseGroups(null);
studentExam.getExam().setStudentExams(null);
}
log.info("Generated {} student exams in {} for exam {}", studentExams.size(), formatDurationFrom(start), examId);
return ResponseEntity.ok().body(studentExams);
}
use of de.tum.in.www1.artemis.domain.exam.StudentExam in project ArTEMiS by ls1intum.
the class ExerciseDeletionService method delete.
/**
* Delete the exercise by id and all its participations.
*
* @param exerciseId the exercise to be deleted
* @param deleteStudentReposBuildPlans whether the student repos and build plans should be deleted (can be true for programming exercises and should be false for all other exercise types)
* @param deleteBaseReposBuildPlans whether the template and solution repos and build plans should be deleted (can be true for programming exercises and should be false for all other exercise types)
*/
// ok
@Transactional
public void delete(long exerciseId, boolean deleteStudentReposBuildPlans, boolean deleteBaseReposBuildPlans) {
// Delete has a transactional mechanism. Therefore, all lazy objects that are deleted below, should be fetched when needed.
final var exercise = exerciseRepository.findByIdElseThrow(exerciseId);
log.info("Checking if exercise {} is modeling exercise", exercise.getId());
if (exercise instanceof ModelingExercise) {
log.info("Deleting clusters, elements and cancel scheduled operations of exercise {}", exercise.getId());
modelingExerciseService.deleteClustersAndElements((ModelingExercise) exercise);
modelingExerciseService.cancelScheduledOperations(exerciseId);
}
participantScoreRepository.deleteAllByExerciseIdTransactional(exerciseId);
// delete all exercise units linking to the exercise
List<ExerciseUnit> exerciseUnits = this.exerciseUnitRepository.findByIdWithLearningGoalsBidirectional(exerciseId);
for (ExerciseUnit exerciseUnit : exerciseUnits) {
this.lectureUnitService.removeLectureUnit(exerciseUnit);
}
// delete all plagiarism results belonging to this exercise
plagiarismResultRepository.deletePlagiarismResultsByExerciseId(exerciseId);
// delete all participations belonging to this exercise, this will also delete submissions, results, feedback, complaints, etc.
participationService.deleteAllByExerciseId(exercise.getId(), deleteStudentReposBuildPlans, deleteStudentReposBuildPlans);
// clean up the many-to-many relationship to avoid problems when deleting the entities but not the relationship table
// to avoid a ConcurrentModificationException, we need to use a copy of the set
var exampleSubmissions = new HashSet<>(exercise.getExampleSubmissions());
for (ExampleSubmission exampleSubmission : exampleSubmissions) {
exampleSubmissionService.deleteById(exampleSubmission.getId());
}
// make sure tutor participations are deleted before the exercise is deleted
tutorParticipationRepository.deleteAllByAssessedExerciseId(exercise.getId());
if (exercise.isExamExercise()) {
Exam exam = examRepository.findOneWithEagerExercisesGroupsAndStudentExams(exercise.getExerciseGroup().getExam().getId());
for (StudentExam studentExam : exam.getStudentExams()) {
if (studentExam.getExercises().contains(exercise)) {
// remove exercise reference from student exam
List<Exercise> exerciseList = studentExam.getExercises();
exerciseList.remove(exercise);
studentExam.setExercises(exerciseList);
studentExamRepository.save(studentExam);
}
}
}
// Programming exercises have some special stuff that needs to be cleaned up (solution/template participation, build plans, etc.).
if (exercise instanceof ProgrammingExercise) {
// TODO: delete all schedules related to this programming exercise
programmingExerciseService.delete(exercise.getId(), deleteBaseReposBuildPlans);
} else {
// delete text assessment knowledge if exercise is of type TextExercise and if no other exercise uses same knowledge
if (exercise instanceof TextExercise) {
// explicitly load the text exercise as such so that the knowledge is eagerly loaded as well
TextExercise textExercise = textExerciseRepository.findByIdElseThrow(exercise.getId());
if (textExercise.getKnowledge() != null) {
textAssessmentKnowledgeService.deleteKnowledge(textExercise.getKnowledge().getId(), textExercise.getId());
}
} else // delete model assessment knowledge if exercise is of type ModelExercise and if no other exercise uses same knowledge
if (exercise instanceof ModelingExercise) {
// explicitly load the modeling exercise as such so that the knowledge is eagerly loaded as well
ModelingExercise modelingExercise = modelingExerciseRepository.findByIdElseThrow(exercise.getId());
if (modelingExercise.getKnowledge() != null) {
modelAssessmentKnowledgeService.deleteKnowledge(modelingExercise.getKnowledge().getId(), modelingExercise.getId());
}
}
exerciseRepository.delete(exercise);
}
}
use of de.tum.in.www1.artemis.domain.exam.StudentExam in project ArTEMiS by ls1intum.
the class ExamQuizServiceTest method evaluateQuiz.
@Test
@WithMockUser(username = "instructor1", roles = "INSTRUCTOR")
public void evaluateQuiz() throws Exception {
for (int i = 0; i < numberOfParticipants; i++) {
exam.addRegisteredUser(users.get(i));
}
exam = examRepository.save(exam);
exerciseGroup.setExam(exam);
exerciseGroup = exerciseGroupRepository.save(exerciseGroup);
exam.setExerciseGroups(List.of(exerciseGroup));
quizExercise.setExerciseGroup(exerciseGroup);
quizExercise = quizExerciseService.save(quizExercise);
exerciseGroup.setExercises(Set.of(quizExercise));
assertThat(studentExamRepository.generateStudentExams(exam)).hasSize(numberOfParticipants);
assertThat(studentExamRepository.findByExamId(exam.getId())).hasSize(numberOfParticipants);
assertThat(studentExamService.startExercises(exam.getId())).isEqualTo(numberOfParticipants);
for (int i = 0; i < numberOfParticipants; i++) {
database.changeUser("student" + (i + 1));
QuizSubmission quizSubmission = database.generateSubmissionForThreeQuestions(quizExercise, i + 1, true, ZonedDateTime.now());
request.put("/api/exercises/" + quizExercise.getId() + "/submissions/exam", quizSubmission, HttpStatus.OK);
}
database.changeUser("instructor1");
// All exams should be over before evaluation
for (StudentExam studentExam : studentExamRepository.findByExamId(exam.getId())) {
studentExam.setWorkingTime(0);
studentExamRepository.save(studentExam);
}
Integer numberOfEvaluatedExercises = request.postWithResponseBody("/api/courses/" + course.getId() + "/exams/" + exam.getId() + "/student-exams/evaluate-quiz-exercises", Optional.empty(), Integer.class, HttpStatus.OK);
assertThat(numberOfEvaluatedExercises).isEqualTo(1);
checkStatistics(quizExercise);
studentExamRepository.deleteAll();
// Make sure delete also works if so many objects have been created before
request.delete("/api/courses/" + course.getId() + "/exams/" + exam.getId(), HttpStatus.OK);
userRepository.deleteAll();
}
use of de.tum.in.www1.artemis.domain.exam.StudentExam in project ArTEMiS by ls1intum.
the class ExamQuizServiceTest method evaluateQuiz_twice.
@Test
@WithMockUser(username = "instructor1", roles = "INSTRUCTOR")
public void evaluateQuiz_twice() throws Exception {
for (int i = 0; i < numberOfParticipants; i++) {
exam.addRegisteredUser(users.get(i));
}
exam = examRepository.save(exam);
exerciseGroup.setExam(exam);
exerciseGroup = exerciseGroupRepository.save(exerciseGroup);
exam.setExerciseGroups(List.of(exerciseGroup));
quizExercise.setExerciseGroup(exerciseGroup);
quizExercise = quizExerciseService.save(quizExercise);
exerciseGroup.setExercises(Set.of(quizExercise));
assertThat(studentExamRepository.generateStudentExams(exam)).hasSize(numberOfParticipants);
assertThat(studentExamRepository.findByExamId(exam.getId())).hasSize(numberOfParticipants);
assertThat(studentExamService.startExercises(exam.getId())).isEqualTo(numberOfParticipants);
for (int i = 0; i < numberOfParticipants; i++) {
database.changeUser("student" + (i + 1));
QuizSubmission quizSubmission = database.generateSubmissionForThreeQuestions(quizExercise, i + 1, true, ZonedDateTime.now());
request.put("/api/exercises/" + quizExercise.getId() + "/submissions/exam", quizSubmission, HttpStatus.OK);
}
database.changeUser("instructor1");
// All exams should be over before evaluation
for (StudentExam studentExam : studentExamRepository.findByExamId(exam.getId())) {
studentExam.setWorkingTime(0);
studentExamRepository.save(studentExam);
}
Integer numberOfEvaluatedExercises = request.postWithResponseBody("/api/courses/" + course.getId() + "/exams/" + exam.getId() + "/student-exams/evaluate-quiz-exercises", Optional.empty(), Integer.class, HttpStatus.OK);
assertThat(numberOfEvaluatedExercises).isEqualTo(1);
// Evaluate quiz twice
numberOfEvaluatedExercises = request.postWithResponseBody("/api/courses/" + course.getId() + "/exams/" + exam.getId() + "/student-exams/evaluate-quiz-exercises", Optional.empty(), Integer.class, HttpStatus.OK);
assertThat(numberOfEvaluatedExercises).isEqualTo(1);
checkStatistics(quizExercise);
studentExamRepository.deleteAll();
// Make sure delete also works if so many objects have been created before
request.delete("/api/courses/" + course.getId() + "/exams/" + exam.getId(), HttpStatus.OK);
userRepository.deleteAll();
}
Aggregations