Search in sources :

Example 71 with Exam

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

the class JenkinsUserManagementService method addUserToGroups.

/**
 * Adds the Artemis user to a group in Jenkins. Jenkins does not support
 * groups so this function fetches all programming exercises belonging to
 * the groups and assigns the user permissions to them.
 *
 * @param userLogin The user login to add to the group
 * @param groups    The groups to add the user to
 */
@Override
public void addUserToGroups(String userLogin, Set<String> groups) throws ContinuousIntegrationException {
    var exercises = programmingExerciseRepository.findAllByInstructorOrEditorOrTAGroupNameIn(groups);
    log.info("Update Jenkins permissions for programming exercises: " + exercises.stream().map(ProgrammingExercise::getProjectKey).toList());
    // TODO: in case we update a tutor group / role here, the tutor should NOT get access to exam exercises before the exam has finished
    exercises.forEach(exercise -> {
        // The exercise's project key is also the name of the Jenkins job that groups all build plans
        // for students, solution, and template.
        var jobName = exercise.getProjectKey();
        var course = exercise.getCourseViaExerciseGroupOrCourseMember();
        if (groups.contains(course.getInstructorGroupName())) {
            try {
                // We are assigning instructor permissions since the exercise's course instructor group is the same as the one that is specified.
                jenkinsJobPermissionsService.addPermissionsForUserToFolder(userLogin, jobName, JenkinsJobPermission.getInstructorPermissions());
            } catch (IOException e) {
                throw new JenkinsException("Cannot assign instructor permissions to user: " + userLogin, e);
            }
        } else if (groups.contains(course.getEditorGroupName())) {
            try {
                // We are assigning editor permissions since the exercise's course editor group is the same as the one that is specified.
                jenkinsJobPermissionsService.addPermissionsForUserToFolder(userLogin, jobName, JenkinsJobPermission.getEditorPermissions());
            } catch (IOException e) {
                throw new JenkinsException("Cannot assign editor permissions to user: " + userLogin, e);
            }
        } else if (groups.contains(course.getTeachingAssistantGroupName())) {
            try {
                // We are assigning teaching assistant permissions since the exercise's course teaching assistant group is the same as the one that is specified.
                jenkinsJobPermissionsService.addTeachingAssistantPermissionsToUserForFolder(userLogin, jobName);
            } catch (IOException e) {
                throw new JenkinsException("Cannot assign teaching assistant permissions to user: " + userLogin, e);
            }
        }
    });
}
Also used : JenkinsException(de.tum.in.www1.artemis.exception.JenkinsException) IOException(java.io.IOException)

Example 72 with Exam

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

the class ExamResource method createExam.

/**
 * POST /courses/{courseId}/exams : Create a new exam.
 *
 * @param courseId the course to which the exam belongs
 * @param exam     the exam to create
 * @return the ResponseEntity with status 201 (Created) and with body the new exam, or with status 400 (Bad Request) if the exam has already an ID
 * @throws URISyntaxException if the Location URI syntax is incorrect
 */
@PostMapping("/courses/{courseId}/exams")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<Exam> createExam(@PathVariable Long courseId, @RequestBody Exam exam) throws URISyntaxException {
    log.debug("REST request to create an exam : {}", exam);
    if (exam.getId() != null) {
        throw new BadRequestAlertException("A new exam cannot already have an ID", ENTITY_NAME, "idexists");
    }
    checkForExamConflictsElseThrow(courseId, exam);
    // Check that exerciseGroups are not set to prevent manipulation of associated exerciseGroups
    if (!exam.getExerciseGroups().isEmpty()) {
        throw new ConflictException("A new exam cannot have exercise groups yet", ENTITY_NAME, "groupsExist");
    }
    examAccessService.checkCourseAccessForInstructorElseThrow(courseId);
    Exam result = examRepository.save(exam);
    return ResponseEntity.created(new URI("/api/courses/" + courseId + "/exams/" + result.getId())).headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, result.getTitle())).body(result);
}
Also used : BadRequestAlertException(de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException) ConflictException(de.tum.in.www1.artemis.web.rest.errors.ConflictException) URI(java.net.URI) StudentExam(de.tum.in.www1.artemis.domain.exam.StudentExam) Exam(de.tum.in.www1.artemis.domain.exam.Exam) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 73 with Exam

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

the class ExamResource method resetExam.

/**
 * DELETE /courses/{courseId}/exams/{examId}/reset : Reset the exam with the given id.
 * The reset operation deletes all studentExams, participations, submissions and feedback.
 *
 * @param courseId the course to which the exam belongs
 * @param examId   the id of the exam to reset
 * @return the ResponseEntity with status 200 (OK)
 */
@DeleteMapping("/courses/{courseId}/exams/{examId}/reset")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<Exam> resetExam(@PathVariable Long courseId, @PathVariable Long examId) {
    log.info("REST request to reset exam : {}", examId);
    var exam = examRepository.findByIdElseThrow(examId);
    examAccessService.checkCourseAndExamAccessForInstructorElseThrow(courseId, examId);
    examService.reset(exam.getId());
    Exam returnExam = examService.findByIdWithExerciseGroupsAndExercisesElseThrow(examId);
    examService.setExamProperties(returnExam);
    return ResponseEntity.ok(returnExam);
}
Also used : StudentExam(de.tum.in.www1.artemis.domain.exam.StudentExam) Exam(de.tum.in.www1.artemis.domain.exam.Exam) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 74 with Exam

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

the class ExamResource method updateExam.

/**
 * PUT /courses/{courseId}/exams : Updates an existing exam.
 * This route does not save changes to the exercise groups. This should be done via the ExerciseGroupResource.
 *
 * @param courseId    the course to which the exam belongs
 * @param updatedExam the exam to update
 * @return the ResponseEntity with status 200 (OK) and with body the updated exam
 * @throws URISyntaxException if the Location URI syntax is incorrect
 */
@PutMapping("/courses/{courseId}/exams")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<Exam> updateExam(@PathVariable Long courseId, @RequestBody Exam updatedExam) throws URISyntaxException {
    log.debug("REST request to update an exam : {}", updatedExam);
    if (updatedExam.getId() == null) {
        return createExam(courseId, updatedExam);
    }
    checkForExamConflictsElseThrow(courseId, updatedExam);
    examAccessService.checkCourseAndExamAccessForInstructorElseThrow(courseId, updatedExam.getId());
    // Make sure that the original references are preserved.
    Exam originalExam = examRepository.findByIdElseThrow(updatedExam.getId());
    // The Exam Mode cannot be changed after creation -> Compare request with version in the database
    if (updatedExam.isTestExam() != originalExam.isTestExam()) {
        throw new ConflictException("The Exam Mode cannot be changed after creation", ENTITY_NAME, "examModeMismatch");
    }
    // NOTE: Make sure that all references are preserved here
    updatedExam.setExerciseGroups(originalExam.getExerciseGroups());
    updatedExam.setStudentExams(originalExam.getStudentExams());
    updatedExam.setRegisteredUsers(originalExam.getRegisteredUsers());
    Exam result = examRepository.save(updatedExam);
    // We can't test dates for equality as the dates retrieved from the database lose precision. Also use instant to take timezones into account
    Comparator<ZonedDateTime> comparator = Comparator.comparing(date -> date.truncatedTo(ChronoUnit.SECONDS).toInstant());
    if (comparator.compare(originalExam.getVisibleDate(), updatedExam.getVisibleDate()) != 0 || comparator.compare(originalExam.getStartDate(), updatedExam.getStartDate()) != 0) {
        // get all exercises
        Exam examWithExercises = examService.findByIdWithExerciseGroupsAndExercisesElseThrow(result.getId());
        // for all programming exercises in the exam, send their ids for scheduling
        examWithExercises.getExerciseGroups().stream().flatMap(group -> group.getExercises().stream()).filter(ProgrammingExercise.class::isInstance).map(Exercise::getId).forEach(instanceMessageSendService::sendProgrammingExerciseSchedule);
    }
    if (comparator.compare(originalExam.getEndDate(), updatedExam.getEndDate()) != 0) {
        // get all exercises
        Exam examWithExercises = examService.findByIdWithExerciseGroupsAndExercisesElseThrow(result.getId());
        examService.scheduleModelingExercises(examWithExercises);
    }
    return ResponseEntity.ok().headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME, result.getTitle())).body(result);
}
Also used : java.util(java.util) 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) LoggerFactory(org.slf4j.LoggerFactory) StudentExam(de.tum.in.www1.artemis.domain.exam.StudentExam) InstanceMessageSendService(de.tum.in.www1.artemis.service.messaging.InstanceMessageSendService) Value(org.springframework.beans.factory.annotation.Value) TimeLogUtil.formatDurationFrom(de.tum.in.www1.artemis.service.util.TimeLogUtil.formatDurationFrom) ExerciseGroup(de.tum.in.www1.artemis.domain.exam.ExerciseGroup) Duration(java.time.Duration) InputStreamResource(org.springframework.core.io.InputStreamResource) TutorParticipation(de.tum.in.www1.artemis.domain.participation.TutorParticipation) URI(java.net.URI) Path(java.nio.file.Path) Exam(de.tum.in.www1.artemis.domain.exam.Exam) Resource(org.springframework.core.io.Resource) HeaderUtil(de.tum.in.www1.artemis.web.rest.util.HeaderUtil) StudentDTO(de.tum.in.www1.artemis.service.dto.StudentDTO) de.tum.in.www1.artemis.service(de.tum.in.www1.artemis.service) Logger(org.slf4j.Logger) MediaType(org.springframework.http.MediaType) ConflictException(de.tum.in.www1.artemis.web.rest.errors.ConflictException) FileInputStream(java.io.FileInputStream) Role(de.tum.in.www1.artemis.security.Role) AccessForbiddenException(de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenException) File(java.io.File) FileNotFoundException(java.io.FileNotFoundException) Constants(de.tum.in.www1.artemis.config.Constants) de.tum.in.www1.artemis.service.exam(de.tum.in.www1.artemis.service.exam) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) ChronoUnit(java.time.temporal.ChronoUnit) de.tum.in.www1.artemis.domain(de.tum.in.www1.artemis.domain) de.tum.in.www1.artemis.web.rest.dto(de.tum.in.www1.artemis.web.rest.dto) ZonedDateTime.now(java.time.ZonedDateTime.now) org.springframework.web.bind.annotation(org.springframework.web.bind.annotation) ResponseEntity(org.springframework.http.ResponseEntity) ConflictException(de.tum.in.www1.artemis.web.rest.errors.ConflictException) ZonedDateTime(java.time.ZonedDateTime) StudentExam(de.tum.in.www1.artemis.domain.exam.StudentExam) Exam(de.tum.in.www1.artemis.domain.exam.Exam) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 75 with Exam

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

the class ExamResource method getStudentExamForStart.

/**
 * GET /courses/{courseId}/exams/{examId}/start : Get an exam for the exam start.
 *
 * @param courseId the id of the course
 * @param examId   the id of the exam
 * @return the ResponseEntity with status 200 (OK) and with the found student exam (without exercises) as body
 */
@GetMapping("/courses/{courseId}/exams/{examId}/start")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<StudentExam> getStudentExamForStart(@PathVariable Long courseId, @PathVariable Long examId) {
    log.debug("REST request to get exam {} for conduction", examId);
    StudentExam exam = examAccessService.getExamInCourseElseThrow(courseId, examId);
    return ResponseEntity.ok(exam);
}
Also used : StudentExam(de.tum.in.www1.artemis.domain.exam.StudentExam) 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