Search in sources :

Example 11 with QuizSubmission

use of de.tum.in.www1.artemis.domain.quiz.QuizSubmission in project ArTEMiS by ls1intum.

the class ExamQuizService method evaluateSubmissions.

/**
 * // @formatter:off
 * Evaluate the given quiz exercise by performing the following actions for each participation:
 * 1. Get the submission for each participation (there should be only one as in exam mode, the submission gets created upfront and will be updated)
 * - If no submission is found, print a warning and continue as we cannot evaluate that submission
 * - If more than one submission is found, select one of them
 * 2. mark submission and participation as evaluated
 * 3. Create a new result for the selected submission and calculate scores
 * 4. Save the updated submission & participation and the newly created result
 *
 * After processing all participations, the created results will be returned for further processing
 * Note: We ignore test run participations
 * // @formatter:on
 * @param quizExercise the id of the QuizExercise that should be evaluated
 * @return the newly generated results
 */
private Set<Result> evaluateSubmissions(@NotNull QuizExercise quizExercise) {
    Set<Result> createdResults = new HashSet<>();
    List<StudentParticipation> studentParticipations = studentParticipationRepository.findAllWithEagerLegalSubmissionsAndEagerResultsByExerciseId(quizExercise.getId());
    for (var participation : studentParticipations) {
        if (!participation.isTestRun()) {
            try {
                // reconnect so that the quiz questions are available later on (otherwise there will be a org.hibernate.LazyInitializationException)
                participation.setExercise(quizExercise);
                Set<Submission> submissions = participation.getSubmissions();
                QuizSubmission quizSubmission;
                if (submissions.isEmpty()) {
                    log.warn("Found no submissions for participation {} (Participant {}) in quiz {}", participation.getId(), participation.getParticipant().getName(), quizExercise.getId());
                    continue;
                } else if (submissions.size() > 1) {
                    log.warn("Found multiple ({}) submissions for participation {} (Participant {}) in quiz {}, taking the one with highest id", submissions.size(), participation.getId(), participation.getParticipant().getName(), quizExercise.getId());
                    List<Submission> submissionsList = new ArrayList<>(submissions);
                    // Load submission with highest id
                    submissionsList.sort(Comparator.comparing(Submission::getId).reversed());
                    quizSubmission = (QuizSubmission) submissionsList.get(0);
                } else {
                    quizSubmission = (QuizSubmission) submissions.iterator().next();
                }
                participation.setInitializationState(InitializationState.FINISHED);
                boolean resultExisting = false;
                // create new result if none is existing
                Result result;
                if (participation.getResults().isEmpty()) {
                    result = new Result().participation(participation);
                } else {
                    resultExisting = true;
                    result = participation.getResults().iterator().next();
                }
                // Only create Results once after the first evaluation
                if (!resultExisting) {
                    // delete result from quizSubmission, to be able to set a new one
                    if (quizSubmission.getLatestResult() != null) {
                        resultService.deleteResultWithComplaint(quizSubmission.getLatestResult().getId());
                    }
                    result.setRated(true);
                    result.setAssessmentType(AssessmentType.AUTOMATIC);
                    result.setCompletionDate(ZonedDateTime.now());
                    // set submission to calculate scores
                    result.setSubmission(quizSubmission);
                    // calculate scores and update result and submission accordingly
                    quizSubmission.calculateAndUpdateScores(quizExercise);
                    result.evaluateQuizSubmission();
                    // remove submission to follow save order for ordered collections
                    result.setSubmission(null);
                    // NOTE: we save participation, submission and result here individually so that one exception (e.g. duplicated key) cannot destroy multiple student answers
                    submissionRepository.save(quizSubmission);
                    result = resultRepository.save(result);
                    // add result to participation
                    participation.addResult(result);
                    studentParticipationRepository.save(participation);
                    // add result to submission
                    result.setSubmission(quizSubmission);
                    quizSubmission.addResult(result);
                    submissionRepository.save(quizSubmission);
                    // Add result so that it can be returned (and processed later)
                    createdResults.add(result);
                }
            } catch (Exception e) {
                log.error("Exception in evaluateExamQuizExercise() for user {} in quiz {}: {}", participation.getParticipantIdentifier(), quizExercise.getId(), e.getMessage(), e);
            }
        }
    }
    return createdResults;
}
Also used : QuizSubmission(de.tum.in.www1.artemis.domain.quiz.QuizSubmission) Submission(de.tum.in.www1.artemis.domain.Submission) StudentParticipation(de.tum.in.www1.artemis.domain.participation.StudentParticipation) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) Result(de.tum.in.www1.artemis.domain.Result) QuizSubmission(de.tum.in.www1.artemis.domain.quiz.QuizSubmission)

Example 12 with QuizSubmission

use of de.tum.in.www1.artemis.domain.quiz.QuizSubmission in project ArTEMiS by ls1intum.

the class QuizSubmissionResource method submitQuizForExam.

/**
 * PUT /exercises/:exerciseId/submissions/exam : Update a QuizSubmission for exam mode
 *
 * @param exerciseId        the id of the exercise for which to update the submission
 * @param quizSubmission    the quizSubmission to update
 * @return                  the ResponseEntity with status 200 and body the result or the appropriate error code.
 */
@PutMapping("exercises/{exerciseId}/submissions/exam")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<QuizSubmission> submitQuizForExam(@PathVariable Long exerciseId, @RequestBody QuizSubmission quizSubmission) {
    long start = System.currentTimeMillis();
    log.debug("REST request to submit QuizSubmission for exam : {}", quizSubmission);
    // recreate pointers back to submission in each submitted answer
    for (SubmittedAnswer submittedAnswer : quizSubmission.getSubmittedAnswers()) {
        submittedAnswer.setSubmission(quizSubmission);
    }
    QuizExercise quizExercise = quizExerciseRepository.findByIdWithQuestionsElseThrow(exerciseId);
    User user = userRepository.getUserWithGroupsAndAuthorities();
    // Apply further checks if it is an exam submission
    examSubmissionService.checkSubmissionAllowanceElseThrow(quizExercise, user);
    // Prevent multiple submissions (currently only for exam submissions)
    quizSubmission = (QuizSubmission) examSubmissionService.preventMultipleSubmissions(quizExercise, quizSubmission, user);
    QuizSubmission updatedQuizSubmission = quizSubmissionService.saveSubmissionForExamMode(quizExercise, quizSubmission, user.getLogin());
    long end = System.currentTimeMillis();
    log.info("submitQuizForExam took {}ms for exercise {} and user {}", end - start, exerciseId, user.getLogin());
    return ResponseEntity.ok(updatedQuizSubmission);
}
Also used : SubmittedAnswer(de.tum.in.www1.artemis.domain.quiz.SubmittedAnswer) QuizSubmission(de.tum.in.www1.artemis.domain.quiz.QuizSubmission) User(de.tum.in.www1.artemis.domain.User) QuizExercise(de.tum.in.www1.artemis.domain.quiz.QuizExercise) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 13 with QuizSubmission

use of de.tum.in.www1.artemis.domain.quiz.QuizSubmission in project ArTEMiS by ls1intum.

the class QuizSubmissionResource method submitForPractice.

/**
 * POST /exercises/:exerciseId/submissions/practice : Submit a new quizSubmission for practice mode.
 *
 * @param exerciseId     the id of the exercise for which to init a participation
 * @param quizSubmission the quizSubmission to submit
 * @return the ResponseEntity with status 200 (OK) and the Result as its body, or with status 4xx if the request is invalid
 */
@PostMapping("/exercises/{exerciseId}/submissions/practice")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<Result> submitForPractice(@PathVariable Long exerciseId, @RequestBody QuizSubmission quizSubmission) {
    log.debug("REST request to submit QuizSubmission for practice : {}", quizSubmission);
    // recreate pointers back to submission in each submitted answer
    for (SubmittedAnswer submittedAnswer : quizSubmission.getSubmittedAnswers()) {
        submittedAnswer.setSubmission(quizSubmission);
    }
    if (quizSubmission.getId() != null) {
        return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, ENTITY_NAME, "idexists", "A new quizSubmission cannot already have an ID.")).body(null);
    }
    QuizExercise quizExercise = quizExerciseRepository.findByIdWithQuestionsElseThrow(exerciseId);
    User user = userRepository.getUserWithGroupsAndAuthorities();
    if (!authCheckService.isAllowedToSeeExercise(quizExercise, user)) {
        return ResponseEntity.status(403).headers(HeaderUtil.createFailureAlert(applicationName, true, "submission", "Forbidden", "You are not allowed to participate in this exercise.")).body(null);
    }
    // Note that exam quiz exercises do not have an end date, so we need to check in that order
    if (!Boolean.TRUE.equals(quizExercise.isIsOpenForPractice()) || !quizExercise.isQuizEnded()) {
        return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "submission", "exerciseNotOpenForPractice", "The exercise is not open for practice or hasn't ended yet.")).body(null);
    }
    // the following method either reuses an existing participation or creates a new one
    StudentParticipation participation = participationService.startExercise(quizExercise, user, false);
    // we set the exercise again to prevent issues with lazy loaded quiz questions
    participation.setExercise(quizExercise);
    // update and save submission
    Result result = quizSubmissionService.submitForPractice(quizSubmission, quizExercise, participation);
    // The quizScheduler is usually responsible for updating the participation to FINISHED in the database. If quizzes where the student did not participate are used for
    // practice, the QuizScheduler does not update the participation, that's why we update it manually here
    participation.setInitializationState(InitializationState.FINISHED);
    studentParticipationRepository.saveAndFlush(participation);
    // remove some redundant or unnecessary data that is not needed on client side
    for (SubmittedAnswer answer : quizSubmission.getSubmittedAnswers()) {
        answer.getQuizQuestion().setQuizQuestionStatistic(null);
    }
    quizExercise.setQuizPointStatistic(null);
    quizExercise.setCourse(null);
    messagingService.broadcastNewResult(result.getParticipation(), result);
    // return result with quizSubmission, participation and quiz exercise (including the solution)
    return ResponseEntity.ok(result);
}
Also used : SubmittedAnswer(de.tum.in.www1.artemis.domain.quiz.SubmittedAnswer) User(de.tum.in.www1.artemis.domain.User) StudentParticipation(de.tum.in.www1.artemis.domain.participation.StudentParticipation) QuizExercise(de.tum.in.www1.artemis.domain.quiz.QuizExercise) Result(de.tum.in.www1.artemis.domain.Result) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 14 with QuizSubmission

use of de.tum.in.www1.artemis.domain.quiz.QuizSubmission in project ArTEMiS by ls1intum.

the class ExamQuizServiceTest method evaluateQuizWithMultipleSubmissions.

@Test
@WithMockUser(username = "instructor1", roles = "INSTRUCTOR")
public void evaluateQuizWithMultipleSubmissions() 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++) {
        final var user = database.getUserByLogin("student" + (i + 1));
        database.changeUser(user.getLogin());
        QuizSubmission quizSubmission = database.generateSubmissionForThreeQuestions(quizExercise, i + 1, true, ZonedDateTime.now());
        request.put("/api/exercises/" + quizExercise.getId() + "/submissions/exam", quizSubmission, HttpStatus.OK);
        // add another submission manually to trigger multiple submission branch of evaluateQuizSubmission
        final var studentParticipation = studentParticipationRepository.findWithEagerLegalSubmissionsByExerciseIdAndStudentLogin(quizExercise.getId(), user.getLogin()).get();
        QuizSubmission quizSubmission2 = database.generateSubmissionForThreeQuestions(quizExercise, i + 1, true, ZonedDateTime.now());
        quizSubmission2.setParticipation(studentParticipation);
        quizSubmissionRepository.save(quizSubmission2);
    }
    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();
}
Also used : StudentExam(de.tum.in.www1.artemis.domain.exam.StudentExam) WithMockUser(org.springframework.security.test.context.support.WithMockUser) Test(org.junit.jupiter.api.Test) AbstractSpringIntegrationBambooBitbucketJiraTest(de.tum.in.www1.artemis.AbstractSpringIntegrationBambooBitbucketJiraTest)

Example 15 with QuizSubmission

use of de.tum.in.www1.artemis.domain.quiz.QuizSubmission in project Artemis by ls1intum.

the class QuizSubmissionService method submitForPractice.

/**
 * Submit the given submission for practice
 *
 * @param quizSubmission the submission to submit
 * @param quizExercise   the exercise to submit in
 * @param participation  the participation where the result should be saved
 * @return the result entity
 */
public Result submitForPractice(QuizSubmission quizSubmission, QuizExercise quizExercise, Participation participation) {
    // update submission properties
    quizSubmission.setSubmitted(true);
    quizSubmission.setType(SubmissionType.MANUAL);
    quizSubmission.setSubmissionDate(ZonedDateTime.now());
    // calculate scores
    quizSubmission.calculateAndUpdateScores(quizExercise);
    // save parent submission object
    quizSubmission = quizSubmissionRepository.save(quizSubmission);
    // create result
    Result result = new Result().participation(participation);
    result.setRated(false);
    result.setAssessmentType(AssessmentType.AUTOMATIC);
    result.setCompletionDate(ZonedDateTime.now());
    // save result
    result = resultRepository.save(result);
    // setup result - submission relation
    result.setSubmission(quizSubmission);
    // calculate score and update result accordingly
    result.evaluateQuizSubmission();
    quizSubmission.addResult(result);
    quizSubmission.setParticipation(participation);
    // save submission to set result index column
    quizSubmissionRepository.save(quizSubmission);
    // save result to store score
    resultRepository.save(result);
    // result.participation.exercise.quizQuestions turn into proxy objects after saving, so we need to set it again to prevent problems later on
    result.setParticipation(participation);
    // add result to statistics
    quizScheduleService.addResultForStatisticUpdate(quizExercise.getId(), result);
    log.debug("submit practice quiz finished: {}", quizSubmission);
    return result;
}
Also used : Result(de.tum.in.www1.artemis.domain.Result)

Aggregations

QuizSubmission (de.tum.in.www1.artemis.domain.quiz.QuizSubmission)28 QuizExercise (de.tum.in.www1.artemis.domain.quiz.QuizExercise)20 StudentParticipation (de.tum.in.www1.artemis.domain.participation.StudentParticipation)19 Result (de.tum.in.www1.artemis.domain.Result)17 SubmittedAnswer (de.tum.in.www1.artemis.domain.quiz.SubmittedAnswer)11 User (de.tum.in.www1.artemis.domain.User)10 PreAuthorize (org.springframework.security.access.prepost.PreAuthorize)10 StudentExam (de.tum.in.www1.artemis.domain.exam.StudentExam)8 QuizSubmissionException (de.tum.in.www1.artemis.exception.QuizSubmissionException)8 WithMockUser (org.springframework.security.test.context.support.WithMockUser)8 AbstractSpringIntegrationBambooBitbucketJiraTest (de.tum.in.www1.artemis.AbstractSpringIntegrationBambooBitbucketJiraTest)6 ModelingExercise (de.tum.in.www1.artemis.domain.modeling.ModelingExercise)6 ModelingSubmission (de.tum.in.www1.artemis.domain.modeling.ModelingSubmission)6 EntityNotFoundException (de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException)6 Test (org.junit.jupiter.api.Test)6 Submission (de.tum.in.www1.artemis.domain.Submission)4 AssessmentType (de.tum.in.www1.artemis.domain.enumeration.AssessmentType)4 InitializationState (de.tum.in.www1.artemis.domain.enumeration.InitializationState)4 ModelingPlagiarismResult (de.tum.in.www1.artemis.domain.plagiarism.modeling.ModelingPlagiarismResult)4 TextPlagiarismResult (de.tum.in.www1.artemis.domain.plagiarism.text.TextPlagiarismResult)4