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);
}
}
});
}
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);
}
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);
}
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);
}
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);
}
Aggregations