Search in sources :

Example 86 with Exam

use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.

the class ModelingExerciseResource method updateModelingExercise.

/**
 * PUT modeling-exercises : Updates an existing modelingExercise.
 *
 * @param modelingExercise the modelingExercise to update
 * @param notificationText the text shown to students
 * @return the ResponseEntity with status 200 (OK) and with body the updated modelingExercise, or with status 400 (Bad Request) if the modelingExercise is not valid, or with
 *         status 500 (Internal Server Error) if the modelingExercise couldn't be updated
 * @throws URISyntaxException if the Location URI syntax is incorrect
 */
@PutMapping("modeling-exercises")
@PreAuthorize("hasRole('EDITOR')")
public ResponseEntity<ModelingExercise> updateModelingExercise(@RequestBody ModelingExercise modelingExercise, @RequestParam(value = "notificationText", required = false) String notificationText) throws URISyntaxException {
    log.debug("REST request to update ModelingExercise : {}", modelingExercise);
    if (modelingExercise.getId() == null) {
        return createModelingExercise(modelingExercise);
    }
    // validates general settings: points, dates
    modelingExercise.validateGeneralSettings();
    // Valid exercises have set either a course or an exerciseGroup
    modelingExercise.checkCourseAndExerciseGroupExclusivity(ENTITY_NAME);
    // Check that the user is authorized to update the exercise
    var user = userRepository.getUserWithGroupsAndAuthorities();
    // Important: use the original exercise for permission check
    final ModelingExercise modelingExerciseBeforeUpdate = modelingExerciseRepository.findByIdElseThrow(modelingExercise.getId());
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.EDITOR, modelingExerciseBeforeUpdate, user);
    // Forbid changing the course the exercise belongs to.
    if (!Objects.equals(modelingExerciseBeforeUpdate.getCourseViaExerciseGroupOrCourseMember().getId(), modelingExercise.getCourseViaExerciseGroupOrCourseMember().getId())) {
        throw new ConflictException("Exercise course id does not match the stored course id", ENTITY_NAME, "cannotChangeCourseId");
    }
    // Forbid conversion between normal course exercise and exam exercise
    exerciseService.checkForConversionBetweenExamAndCourseExercise(modelingExercise, modelingExerciseBeforeUpdate, ENTITY_NAME);
    ModelingExercise updatedModelingExercise = modelingExerciseRepository.save(modelingExercise);
    exerciseService.logUpdate(modelingExercise, modelingExercise.getCourseViaExerciseGroupOrCourseMember(), user);
    exerciseService.updatePointsInRelatedParticipantScores(modelingExerciseBeforeUpdate, updatedModelingExercise);
    participationRepository.removeIndividualDueDatesIfBeforeDueDate(updatedModelingExercise, modelingExerciseBeforeUpdate.getDueDate());
    modelingExerciseService.scheduleOperations(updatedModelingExercise.getId());
    exerciseService.checkExampleSubmissions(updatedModelingExercise);
    groupNotificationService.checkAndCreateAppropriateNotificationsWhenUpdatingExercise(modelingExerciseBeforeUpdate, updatedModelingExercise, notificationText, instanceMessageSendService);
    return ResponseEntity.ok().headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME, modelingExercise.getId().toString())).body(updatedModelingExercise);
}
Also used : ConflictException(de.tum.in.www1.artemis.web.rest.errors.ConflictException) ModelingExercise(de.tum.in.www1.artemis.domain.modeling.ModelingExercise) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 87 with Exam

use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.

the class ParticipantScoreResource method getScoresOfExam.

/**
 * GET /exams/:examId/exam-scores gets the exam scores of the exam
 * <p>
 * This method represents a server based way to calculate a students achieved points / score in an exam.
 * <p>
 * Currently both this server based calculation method and the traditional client side calculation method is used
 * side-by-side in exam-scores.component.ts.
 * <p>
 * The goal is to switch completely to this much faster server based calculation if the {@link de.tum.in.www1.artemis.service.listeners.ResultListener}
 * has been battle tested enough.
 *
 * @param examId the id of the exam for which to calculate the exam scores
 * @return list of scores for every registered user in the xam
 */
@GetMapping("/exams/{examId}/exam-scores")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<List<ScoreDTO>> getScoresOfExam(@PathVariable Long examId) {
    long start = System.currentTimeMillis();
    log.debug("REST request to get exam scores for exam : {}", examId);
    Exam exam = examRepository.findByIdWithRegisteredUsersExerciseGroupsAndExercisesElseThrow(examId);
    authorizationCheckService.checkHasAtLeastRoleInCourseElseThrow(Role.INSTRUCTOR, exam.getCourse(), null);
    List<ScoreDTO> scoreDTOS = participantScoreService.calculateExamScores(exam);
    log.info("getScoresOfExam took {}ms", System.currentTimeMillis() - start);
    return ResponseEntity.ok().body(scoreDTOS);
}
Also used : ParticipantScoreDTO(de.tum.in.www1.artemis.web.rest.dto.ParticipantScoreDTO) ScoreDTO(de.tum.in.www1.artemis.web.rest.dto.ScoreDTO) Exam(de.tum.in.www1.artemis.domain.exam.Exam) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 88 with Exam

use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.

the class ResultResource method createResultForExternalSubmission.

/**
 * POST exercises/:exerciseId/external-submission-results : Creates a new result for the provided exercise and student (a participation and an empty submission will also be created if they do not exist yet)
 *
 * @param exerciseId The exercise ID for which a result should get created
 * @param studentLogin The student login (username) for which a result should get created
 * @param result The result to be created
 * @return The newly created result
 * @throws URISyntaxException if the Location URI syntax is incorrect
 */
@PostMapping("exercises/{exerciseId}/external-submission-results")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<Result> createResultForExternalSubmission(@PathVariable Long exerciseId, @RequestParam String studentLogin, @RequestBody Result result) throws URISyntaxException {
    log.debug("REST request to create Result for External Submission for Exercise : {}", exerciseId);
    if (result.getParticipation() != null && result.getParticipation().getExercise() != null && !result.getParticipation().getExercise().getId().equals(exerciseId)) {
        throw new BadRequestAlertException("exerciseId in RequestBody doesnt match exerciseId in path!", "Exercise", "400");
    }
    Exercise exercise = exerciseRepository.findByIdElseThrow(exerciseId);
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.INSTRUCTOR, exercise, null);
    if (!exercise.isExamExercise()) {
        if (exercise.getDueDate() == null || ZonedDateTime.now().isBefore(exercise.getDueDate())) {
            return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "externalSubmissionBeforeDueDate", "External submissions are not supported before the exercise due date.")).build();
        }
    } else {
        Exam exam = exercise.getExerciseGroup().getExam();
        ZonedDateTime latestIndividualExamEndDate = examDateService.getLatestIndividualExamEndDate(exam);
        if (latestIndividualExamEndDate == null || ZonedDateTime.now().isBefore(latestIndividualExamEndDate)) {
            return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "externalSubmissionBeforeDueDate", "External submissions are not supported before the end of the exam.")).build();
        }
    }
    if (exercise instanceof QuizExercise) {
        return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "externalSubmissionForQuizExercise", "External submissions are not supported for Quiz exercises.")).build();
    }
    Optional<User> student = userRepository.findOneWithGroupsAndAuthoritiesByLogin(studentLogin);
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.INSTRUCTOR, exercise, null);
    if (student.isEmpty() || !authCheckService.isAtLeastStudentInCourse(exercise.getCourseViaExerciseGroupOrCourseMember(), student.get())) {
        return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "studentNotFound", "The student could not be found in this course.")).build();
    }
    // Check if a result exists already for this exercise and student. If so, do nothing and just inform the instructor.
    Optional<StudentParticipation> optionalParticipation = participationService.findOneByExerciseAndStudentLoginAnyStateWithEagerResults(exercise, studentLogin);
    if (optionalParticipation.isPresent() && optionalParticipation.get().getResults() != null && !optionalParticipation.get().getResults().isEmpty()) {
        return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "resultAlreadyExists", "A result already exists for this student in this exercise.")).build();
    }
    // Create a participation and a submitted empty submission if they do not exist yet
    StudentParticipation participation = participationService.createParticipationWithEmptySubmissionIfNotExisting(exercise, student.get(), SubmissionType.EXTERNAL);
    Submission submission = participationRepository.findByIdWithLegalSubmissionsElseThrow(participation.getId()).findLatestSubmission().get();
    result.setParticipation(participation);
    result.setSubmission(submission);
    // Create a new manual result which can be rated or unrated depending on what was specified in the create form
    Result savedResult = resultService.createNewManualResult(result, exercise instanceof ProgrammingExercise, result.isRated());
    return ResponseEntity.created(new URI("/api/results/" + savedResult.getId())).headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, savedResult.getId().toString())).body(savedResult);
}
Also used : URI(java.net.URI) ProgrammingExerciseStudentParticipation(de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation) StudentParticipation(de.tum.in.www1.artemis.domain.participation.StudentParticipation) QuizExercise(de.tum.in.www1.artemis.domain.quiz.QuizExercise) BadRequestAlertException(de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException) QuizExercise(de.tum.in.www1.artemis.domain.quiz.QuizExercise) ZonedDateTime(java.time.ZonedDateTime) Exam(de.tum.in.www1.artemis.domain.exam.Exam) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 89 with Exam

use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.

the class ComplaintResource method createComplaintForExamExercise.

/**
 * POST complaints/exam/examId: create a new complaint for an exam exercise
 *
 * @param complaint the complaint to create
 * @param principal that wants to complain
 * @param examId the examId of the exam which contains the exercise
 * @return the ResponseEntity with status 201 (Created) and with body the new complaints
 * @throws URISyntaxException if the Location URI syntax is incorrect
 */
// TODO: should be exams/{examId}/(participations/{participationId}/)complaints
@PostMapping("complaints/exam/{examId}")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<Complaint> createComplaintForExamExercise(@PathVariable Long examId, @RequestBody Complaint complaint, Principal principal) throws URISyntaxException {
    log.debug("REST request to save Complaint for exam exercise: {}", complaint);
    if (complaint.getId() != null) {
        throw new BadRequestAlertException("A new complaint cannot already have an id", COMPLAINT_ENTITY_NAME, "idexists");
    }
    if (complaint.getResult() == null || complaint.getResult().getId() == null) {
        throw new BadRequestAlertException("A complaint can be only associated to a result", COMPLAINT_ENTITY_NAME, "noresultid");
    }
    if (complaintRepository.findByResultId(complaint.getResult().getId()).isPresent()) {
        throw new BadRequestAlertException("A complaint for this result already exists", COMPLAINT_ENTITY_NAME, "complaintexists");
    }
    Result result = resultRepository.findByIdElseThrow(complaint.getResult().getId());
    // For non-exam exercises, the POST complaints should be used
    if (!result.getParticipation().getExercise().isExamExercise()) {
        throw new BadRequestAlertException("A complaint for an course exercise cannot be filed using this component", COMPLAINT_ENTITY_NAME, "complaintAboutCourseExerciseWrongComponent");
    }
    authCheckService.isOwnerOfParticipationElseThrow((StudentParticipation) result.getParticipation());
    // To build correct creation alert on the front-end we must check which type is the complaint to apply correct i18n key.
    String entityName = complaint.getComplaintType() == ComplaintType.MORE_FEEDBACK ? MORE_FEEDBACK_ENTITY_NAME : COMPLAINT_ENTITY_NAME;
    Complaint savedComplaint = complaintService.createComplaint(complaint, OptionalLong.of(examId), principal);
    // Remove assessor information from client request
    savedComplaint.getResult().setAssessor(null);
    return ResponseEntity.created(new URI("/api/complaints/" + savedComplaint.getId())).headers(HeaderUtil.createEntityCreationAlert(applicationName, true, entityName, savedComplaint.getId().toString())).body(savedComplaint);
}
Also used : BadRequestAlertException(de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException) URI(java.net.URI) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 90 with Exam

use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.

the class ComplaintResource method createComplaint.

/**
 * POST complaints: create a new complaint
 *
 * @param complaint the complaint to create
 * @param principal that wants to complain
 * @return the ResponseEntity with status 201 (Created) and with body the new complaints
 * @throws URISyntaxException if the Location URI syntax is incorrect
 */
// TODO: should be participations/{participationId}/results/{resultId}/complaints
@PostMapping("complaints")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<Complaint> createComplaint(@RequestBody Complaint complaint, Principal principal) throws URISyntaxException {
    log.debug("REST request to save Complaint: {}", complaint);
    if (complaint.getId() != null) {
        throw new BadRequestAlertException("A new complaint cannot already have an id", COMPLAINT_ENTITY_NAME, "idexists");
    }
    if (complaint.getResult() == null || complaint.getResult().getId() == null) {
        throw new BadRequestAlertException("A complaint can be only associated to a result", COMPLAINT_ENTITY_NAME, "noresultid");
    }
    if (complaintRepository.findByResultId(complaint.getResult().getId()).isPresent()) {
        throw new BadRequestAlertException("A complaint for this result already exists", COMPLAINT_ENTITY_NAME, "complaintexists");
    }
    Result result = resultRepository.findByIdElseThrow(complaint.getResult().getId());
    // For exam exercises, the POST complaints/exam/examId should be used
    if (result.getParticipation().getExercise().isExamExercise()) {
        throw new BadRequestAlertException("A complaint for an exam exercise cannot be filed using this component", COMPLAINT_ENTITY_NAME, "complaintAboutExamExerciseWrongComponent");
    }
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.STUDENT, result.getParticipation().getExercise(), null);
    // To build correct creation alert on the front-end we must check which type is the complaint to apply correct i18n key.
    String entityName = complaint.getComplaintType() == ComplaintType.MORE_FEEDBACK ? MORE_FEEDBACK_ENTITY_NAME : COMPLAINT_ENTITY_NAME;
    Complaint savedComplaint = complaintService.createComplaint(complaint, OptionalLong.empty(), principal);
    // Remove assessor information from client request
    savedComplaint.getResult().setAssessor(null);
    return ResponseEntity.created(new URI("/api/complaints/" + savedComplaint.getId())).headers(HeaderUtil.createEntityCreationAlert(applicationName, true, entityName, savedComplaint.getId().toString())).body(savedComplaint);
}
Also used : BadRequestAlertException(de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException) URI(java.net.URI) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Aggregations

Exam (de.tum.in.www1.artemis.domain.exam.Exam)228 StudentExam (de.tum.in.www1.artemis.domain.exam.StudentExam)180 WithMockUser (org.springframework.security.test.context.support.WithMockUser)164 Test (org.junit.jupiter.api.Test)158 ExerciseGroup (de.tum.in.www1.artemis.domain.exam.ExerciseGroup)92 PreAuthorize (org.springframework.security.access.prepost.PreAuthorize)75 ModelingExercise (de.tum.in.www1.artemis.domain.modeling.ModelingExercise)52 EntityNotFoundException (de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException)48 AbstractSpringIntegrationBambooBitbucketJiraTest (de.tum.in.www1.artemis.AbstractSpringIntegrationBambooBitbucketJiraTest)46 StudentParticipation (de.tum.in.www1.artemis.domain.participation.StudentParticipation)46 QuizExercise (de.tum.in.www1.artemis.domain.quiz.QuizExercise)42 ZonedDateTime (java.time.ZonedDateTime)40 BadRequestAlertException (de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException)38 Course (de.tum.in.www1.artemis.domain.Course)36 GradingScale (de.tum.in.www1.artemis.domain.GradingScale)34 BeforeEach (org.junit.jupiter.api.BeforeEach)30 User (de.tum.in.www1.artemis.domain.User)27 Collectors (java.util.stream.Collectors)26 ModelingSubmission (de.tum.in.www1.artemis.domain.modeling.ModelingSubmission)24 de.tum.in.www1.artemis.repository (de.tum.in.www1.artemis.repository)24