Search in sources :

Example 41 with StudentParticipation

use of de.tum.in.www1.artemis.domain.participation.StudentParticipation in project ArTEMiS by ls1intum.

the class ParticipationTeamWebsocketService method updateSubmission.

/**
 * Updates a modeling or text submission
 *
 * @param participationId id of participation
 * @param submission      updated modeling text submission
 * @param principal       principal of user who wants to update the submission
 * @param topicPath       path of websocket destination topic where to send the new submission
 */
private void updateSubmission(@DestinationVariable Long participationId, @Payload Submission submission, Principal principal, String topicPath) {
    // Without this, custom jpa repository methods don't work in websocket channel.
    SecurityUtils.setAuthorizationObject();
    final StudentParticipation participation = studentParticipationRepository.findByIdElseThrow(participationId);
    // user must belong to the team who owns the participation in order to update a submission
    if (!participation.isOwnedBy(principal.getName())) {
        return;
    }
    final User user = userRepository.getUserWithGroupsAndAuthorities(principal.getName());
    final Exercise exercise = exerciseRepository.findByIdElseThrow(participation.getExercise().getId());
    if (submission instanceof ModelingSubmission && exercise instanceof ModelingExercise) {
        submission = modelingSubmissionService.save((ModelingSubmission) submission, (ModelingExercise) exercise, principal.getName());
        modelingSubmissionService.hideDetails(submission, user);
    } else if (submission instanceof TextSubmission && exercise instanceof TextExercise) {
        submission = textSubmissionService.handleTextSubmission((TextSubmission) submission, (TextExercise) exercise, principal);
        textSubmissionService.hideDetails(submission, user);
    } else {
        throw new IllegalArgumentException("Submission type '" + submission.getType() + "' not allowed.");
    }
    // update the last action date for the user and send out list of team members
    updateValue(lastActionTracker, participationId, principal.getName());
    sendOnlineTeamStudents(participationId);
    SubmissionSyncPayload payload = new SubmissionSyncPayload(submission, user);
    messagingTemplate.convertAndSend(getDestination(participationId, topicPath), payload);
}
Also used : ModelingExercise(de.tum.in.www1.artemis.domain.modeling.ModelingExercise) SubmissionSyncPayload(de.tum.in.www1.artemis.web.websocket.dto.SubmissionSyncPayload) ModelingSubmission(de.tum.in.www1.artemis.domain.modeling.ModelingSubmission) ModelingExercise(de.tum.in.www1.artemis.domain.modeling.ModelingExercise) StudentParticipation(de.tum.in.www1.artemis.domain.participation.StudentParticipation)

Example 42 with StudentParticipation

use of de.tum.in.www1.artemis.domain.participation.StudentParticipation in project ArTEMiS by ls1intum.

the class TextSubmissionService method save.

/**
 * Saves the given submission. Is used for creating and updating text submissions.
 *
 * @param textSubmission the submission that should be saved
 * @param participation  the participation the submission belongs to
 * @param textExercise   the exercise the submission belongs to
 * @param principal      the principal of the user
 * @return the textSubmission entity that was saved to the database
 */
public TextSubmission save(TextSubmission textSubmission, StudentParticipation participation, TextExercise textExercise, Principal principal) {
    // update submission properties
    textSubmission.setSubmissionDate(ZonedDateTime.now());
    textSubmission.setType(SubmissionType.MANUAL);
    textSubmission.setParticipation(participation);
    // remove result from submission (in the unlikely case it is passed here), so that students cannot inject a result
    textSubmission.setResults(new ArrayList<>());
    textSubmission = textSubmissionRepository.save(textSubmission);
    // versioning of submission
    try {
        if (textExercise.isTeamMode()) {
            submissionVersionService.saveVersionForTeam(textSubmission, principal.getName());
        } else if (textExercise.isExamExercise()) {
            submissionVersionService.saveVersionForIndividual(textSubmission, principal.getName());
        }
    } catch (Exception ex) {
        log.error("Text submission version could not be saved", ex);
    }
    participation.addSubmission(textSubmission);
    participation.setInitializationState(InitializationState.FINISHED);
    StudentParticipation savedParticipation = studentParticipationRepository.save(participation);
    if (textSubmission.getId() == null) {
        Optional<Submission> optionalTextSubmission = savedParticipation.findLatestSubmission();
        if (optionalTextSubmission.isPresent()) {
            textSubmission = (TextSubmission) optionalTextSubmission.get();
        }
    }
    return textSubmission;
}
Also used : Submission(de.tum.in.www1.artemis.domain.Submission) TextSubmission(de.tum.in.www1.artemis.domain.TextSubmission) ResponseStatusException(org.springframework.web.server.ResponseStatusException) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) StudentParticipation(de.tum.in.www1.artemis.domain.participation.StudentParticipation)

Example 43 with StudentParticipation

use of de.tum.in.www1.artemis.domain.participation.StudentParticipation 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 44 with StudentParticipation

use of de.tum.in.www1.artemis.domain.participation.StudentParticipation in project ArTEMiS by ls1intum.

the class ExamSubmissionService method preventMultipleSubmissions.

/**
 * We want to prevent multiple submissions for text, modeling, file upload and quiz exercises. Therefore we check if
 * a submission for this exercise+student already exists.
 * - If a submission exists, we will always overwrite this submission, even if the id of the received submission
 *   deviates from the one we've got from the database.
 * - If no submission exists (on creation) we allow adding one (implicitly via repository.save()).
 *
 * TODO: we might want to move this to the SubmissionService
 *
 * @param exercise      the exercise for which the submission should be saved
 * @param submission    the submission
 * @param user          the current user
 * @return the submission. If a submission already exists for the exercise we will set the id
 */
public Submission preventMultipleSubmissions(Exercise exercise, Submission submission, User user) {
    // Return immediately if it is not an exam submissions or if it is a programming exercise
    if (!isExamSubmission(exercise) || exercise instanceof ProgrammingExercise) {
        return submission;
    }
    List<StudentParticipation> participations = participationService.findByExerciseAndStudentIdWithEagerSubmissions(exercise, user.getId());
    if (!participations.isEmpty()) {
        Set<Submission> submissions = participations.get(0).getSubmissions();
        if (!submissions.isEmpty()) {
            Submission existingSubmission = submissions.iterator().next();
            // Instead of creating a new submission, we want to overwrite the already existing submission. Therefore
            // we set the id of the received submission to the id of the existing submission. When repository.save()
            // is invoked the existing submission will be updated.
            submission.setId(existingSubmission.getId());
        }
    }
    return submission;
}
Also used : Submission(de.tum.in.www1.artemis.domain.Submission) ProgrammingExercise(de.tum.in.www1.artemis.domain.ProgrammingExercise) StudentParticipation(de.tum.in.www1.artemis.domain.participation.StudentParticipation)

Example 45 with StudentParticipation

use of de.tum.in.www1.artemis.domain.participation.StudentParticipation in project ArTEMiS by ls1intum.

the class ResultResource method getResultsForExerciseWithPointsPerCriterion.

/**
 * GET /exercises/:exerciseId/results-with-points-per-criterion : get the successful results for an exercise, ordered ascending by build completion date.
 * Also contains for each result the points the student achieved with manual feedback. Those points are grouped as sum for each grading criterion.
 *
 * @param exerciseId of the exercise for which to retrieve the results.
 * @param withSubmissions defines if submissions are loaded from the database for the results.
 * @return the ResponseEntity with status 200 (OK) and the list of results with points in body.
 */
@GetMapping("exercises/{exerciseId}/results-with-points-per-criterion")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<List<ResultWithPointsPerGradingCriterionDTO>> getResultsForExerciseWithPointsPerCriterion(@PathVariable Long exerciseId, @RequestParam(defaultValue = "true") boolean withSubmissions) {
    final Exercise exercise = exerciseRepository.findByIdElseThrow(exerciseId);
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.INSTRUCTOR, exercise, null);
    final List<StudentParticipation> participations;
    if (exercise.isExamExercise()) {
        participations = studentParticipationRepository.findByExerciseIdWithEagerSubmissionsResultAssessorFeedbacksIgnoreTestRuns(exerciseId);
    } else {
        participations = studentParticipationRepository.findByExerciseIdWithEagerSubmissionsResultAssessorFeedbacks(exerciseId);
    }
    final Course course = exercise.getCourseViaExerciseGroupOrCourseMember();
    final List<Result> results = resultsForExercise(exercise, participations, withSubmissions);
    final List<ResultWithPointsPerGradingCriterionDTO> resultsWithPoints = results.stream().map(result -> resultRepository.calculatePointsPerGradingCriterion(result, course)).toList();
    return ResponseEntity.ok().body(resultsWithPoints);
}
Also used : ContinuousIntegrationException(de.tum.in.www1.artemis.exception.ContinuousIntegrationException) SecurityUtils(de.tum.in.www1.artemis.security.SecurityUtils) WebsocketMessagingService(de.tum.in.www1.artemis.service.WebsocketMessagingService) de.tum.in.www1.artemis.repository(de.tum.in.www1.artemis.repository) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize) BadRequestAlertException(de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException) URISyntaxException(java.net.URISyntaxException) ZonedDateTime(java.time.ZonedDateTime) Participation(de.tum.in.www1.artemis.domain.participation.Participation) LoggerFactory(org.slf4j.LoggerFactory) ParticipationService(de.tum.in.www1.artemis.service.ParticipationService) ArrayList(java.util.ArrayList) ResultService(de.tum.in.www1.artemis.service.ResultService) ContinuousIntegrationService(de.tum.in.www1.artemis.service.connectors.ContinuousIntegrationService) Value(org.springframework.beans.factory.annotation.Value) ProgrammingExerciseStudentParticipation(de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation) ProgrammingExerciseParticipation(de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation) AuthorizationCheckService(de.tum.in.www1.artemis.service.AuthorizationCheckService) URI(java.net.URI) Exam(de.tum.in.www1.artemis.domain.exam.Exam) ResultWithPointsPerGradingCriterionDTO(de.tum.in.www1.artemis.web.rest.dto.ResultWithPointsPerGradingCriterionDTO) Nullable(javax.annotation.Nullable) ExamDateService(de.tum.in.www1.artemis.service.exam.ExamDateService) HeaderUtil(de.tum.in.www1.artemis.web.rest.util.HeaderUtil) Logger(org.slf4j.Logger) BuildPlanType(de.tum.in.www1.artemis.domain.enumeration.BuildPlanType) QuizExercise(de.tum.in.www1.artemis.domain.quiz.QuizExercise) ProgrammingExerciseParticipationService(de.tum.in.www1.artemis.service.programming.ProgrammingExerciseParticipationService) ProgrammingExerciseGradingService(de.tum.in.www1.artemis.service.programming.ProgrammingExerciseGradingService) SubmissionType(de.tum.in.www1.artemis.domain.enumeration.SubmissionType) Role(de.tum.in.www1.artemis.security.Role) AccessForbiddenException(de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenException) Constants(de.tum.in.www1.artemis.config.Constants) HttpStatus(org.springframework.http.HttpStatus) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) List(java.util.List) de.tum.in.www1.artemis.domain(de.tum.in.www1.artemis.domain) org.springframework.web.bind.annotation(org.springframework.web.bind.annotation) Optional(java.util.Optional) StudentParticipation(de.tum.in.www1.artemis.domain.participation.StudentParticipation) LtiService(de.tum.in.www1.artemis.service.connectors.LtiService) ResponseEntity(org.springframework.http.ResponseEntity) QuizExercise(de.tum.in.www1.artemis.domain.quiz.QuizExercise) ResultWithPointsPerGradingCriterionDTO(de.tum.in.www1.artemis.web.rest.dto.ResultWithPointsPerGradingCriterionDTO) ProgrammingExerciseStudentParticipation(de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation) StudentParticipation(de.tum.in.www1.artemis.domain.participation.StudentParticipation) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Aggregations

StudentParticipation (de.tum.in.www1.artemis.domain.participation.StudentParticipation)219 Test (org.junit.jupiter.api.Test)118 WithMockUser (org.springframework.security.test.context.support.WithMockUser)112 ModelingSubmission (de.tum.in.www1.artemis.domain.modeling.ModelingSubmission)60 ModelingExercise (de.tum.in.www1.artemis.domain.modeling.ModelingExercise)50 ProgrammingExerciseStudentParticipation (de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation)48 ZonedDateTime (java.time.ZonedDateTime)44 QuizExercise (de.tum.in.www1.artemis.domain.quiz.QuizExercise)42 EntityNotFoundException (de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException)40 AbstractSpringIntegrationBambooBitbucketJiraTest (de.tum.in.www1.artemis.AbstractSpringIntegrationBambooBitbucketJiraTest)36 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)36 Exam (de.tum.in.www1.artemis.domain.exam.Exam)30 PreAuthorize (org.springframework.security.access.prepost.PreAuthorize)30 TextPlagiarismResult (de.tum.in.www1.artemis.domain.plagiarism.text.TextPlagiarismResult)28 de.tum.in.www1.artemis.repository (de.tum.in.www1.artemis.repository)28 ModelingPlagiarismResult (de.tum.in.www1.artemis.domain.plagiarism.modeling.ModelingPlagiarismResult)26 de.tum.in.www1.artemis.domain (de.tum.in.www1.artemis.domain)24 StudentExam (de.tum.in.www1.artemis.domain.exam.StudentExam)24 Participation (de.tum.in.www1.artemis.domain.participation.Participation)24 Collectors (java.util.stream.Collectors)24