use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ExamRegistrationService method registerStudentsForExam.
/**
* Add multiple users to the students of the exam so that they can access the exam
* The passed list of UserDTOs must include the registration number (the other entries are currently ignored and can be left out)
* Note: registration based on other user attributes (e.g. email, name, login) is currently NOT supported
* <p>
* This method first tries to find the student in the internal Artemis user database (because the user is most probably already using Artemis).
* In case the user cannot be found, we additionally search the (TUM) LDAP in case it is configured properly.
*
* @param courseId the id of the course
* @param examId the id of the exam
* @param studentDTOs the list of students (with at least registration number) who should get access to the exam
* @return the list of students who could not be registered for the exam, because they could NOT be found in the Artemis database and could NOT be found in the TUM LDAP
*/
public List<StudentDTO> registerStudentsForExam(Long courseId, Long examId, List<StudentDTO> studentDTOs) {
var course = courseRepository.findByIdElseThrow(courseId);
var exam = examRepository.findWithRegisteredUsersById(examId).orElseThrow(() -> new EntityNotFoundException("Exam", examId));
List<StudentDTO> notFoundStudentsDTOs = new ArrayList<>();
for (var studentDto : studentDTOs) {
var registrationNumber = studentDto.getRegistrationNumber();
var login = studentDto.getLogin();
Optional<User> optionalStudent = userService.findUserAndAddToCourse(registrationNumber, course.getStudentGroupName(), Role.STUDENT, login);
if (optionalStudent.isEmpty()) {
notFoundStudentsDTOs.add(studentDto);
} else {
exam.addRegisteredUser(optionalStudent.get());
}
}
examRepository.save(exam);
try {
User currentUser = userRepository.getUserWithGroupsAndAuthorities();
Map<String, Object> userData = new HashMap<>();
userData.put("exam", exam.getTitle());
for (var i = 0; i < studentDTOs.size(); i++) {
var studentDTO = studentDTOs.get(i);
userData.put("student" + i, studentDTO.toDatabaseString());
}
AuditEvent auditEvent = new AuditEvent(currentUser.getLogin(), Constants.ADD_USER_TO_EXAM, userData);
auditEventRepository.add(auditEvent);
log.info("User {} has added multiple users {} to the exam {} with id {}", currentUser.getLogin(), studentDTOs, exam.getTitle(), exam.getId());
} catch (Exception ex) {
log.warn("Could not add audit event to audit log", ex);
}
return notFoundStudentsDTOs;
}
use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ExamRegistrationService method unregisterStudentFromExam.
/**
* @param examId the exam for which a student should be unregistered
* @param deleteParticipationsAndSubmission whether the participations and submissions of the student should be deleted
* @param student the user object that should be unregistered
*/
public void unregisterStudentFromExam(Long examId, boolean deleteParticipationsAndSubmission, User student) {
var exam = examRepository.findWithRegisteredUsersById(examId).orElseThrow(() -> new EntityNotFoundException("Exam", examId));
exam.removeRegisteredUser(student);
// Note: we intentionally do not remove the user from the course, because the student might just have "unregistered" from the exam, but should
// still have access to the course.
examRepository.save(exam);
// The student exam might already be generated, then we need to delete it
Optional<StudentExam> optionalStudentExam = studentExamRepository.findWithExercisesByUserIdAndExamId(student.getId(), exam.getId());
optionalStudentExam.ifPresent(studentExam -> removeStudentExam(studentExam, deleteParticipationsAndSubmission));
User currentUser = userRepository.getUserWithGroupsAndAuthorities();
AuditEvent auditEvent = new AuditEvent(currentUser.getLogin(), Constants.REMOVE_USER_FROM_EXAM, "exam=" + exam.getTitle(), "user=" + student.getLogin());
auditEventRepository.add(auditEvent);
log.info("User {} has removed user {} from the exam {} with id {}. This also deleted a potentially existing student exam with all its participations and submissions.", currentUser.getLogin(), student.getLogin(), exam.getTitle(), exam.getId());
}
use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ExamRegistrationService method addAllStudentsOfCourseToExam.
/**
* Adds all students registered in the course to the given exam
*
* @param courseId Id of the course
* @param examId Id of the exam
*/
public void addAllStudentsOfCourseToExam(Long courseId, Long examId) {
Course course = courseRepository.findByIdElseThrow(courseId);
var students = userRepository.getStudents(course);
var exam = examRepository.findByIdWithRegisteredUsersElseThrow(examId);
Map<String, Object> userData = new HashMap<>();
userData.put("exam", exam.getTitle());
for (int i = 0; i < students.size(); i++) {
var student = students.get(i);
if (!exam.getRegisteredUsers().contains(student) && !student.getAuthorities().contains(ADMIN_AUTHORITY) && !student.getGroups().contains(course.getInstructorGroupName())) {
exam.addRegisteredUser(student);
userData.put("student " + i, student.toDatabaseString());
}
}
examRepository.save(exam);
AuditEvent auditEvent = new AuditEvent(userRepository.getUser().getLogin(), Constants.ADD_USER_TO_EXAM, userData);
auditEventRepository.add(auditEvent);
}
use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ExamService method validateForStudentExamGeneration.
/**
* Validates exercise settings.
*
* @param exam exam which is validated
* @throws BadRequestAlertException an exception if the exam is not configured correctly
*/
public void validateForStudentExamGeneration(Exam exam) throws BadRequestAlertException {
List<ExerciseGroup> exerciseGroups = exam.getExerciseGroups();
long numberOfExercises = exam.getNumberOfExercisesInExam() != null ? exam.getNumberOfExercisesInExam() : 0;
long numberOfOptionalExercises = numberOfExercises - exerciseGroups.stream().filter(ExerciseGroup::getIsMandatory).count();
// Ensure that all exercise groups have at least one exercise
for (ExerciseGroup exerciseGroup : exam.getExerciseGroups()) {
if (exerciseGroup.getExercises().isEmpty()) {
throw new BadRequestAlertException("All exercise groups must have at least one exercise", "Exam", "artemisApp.exam.validation.atLeastOneExercisePerExerciseGroup");
}
}
// Check that numberOfExercisesInExam is set
if (exam.getNumberOfExercisesInExam() == null) {
throw new BadRequestAlertException("The number of exercises in the exam is not set.", "Exam", "artemisApp.exam.validation.numberOfExercisesInExamNotSet");
}
// Check that there are enough exercise groups
if (exam.getExerciseGroups().size() < exam.getNumberOfExercisesInExam()) {
throw new BadRequestAlertException("The number of exercise groups is too small", "Exam", "artemisApp.exam.validation.tooFewExerciseGroups");
}
// Check that there are not too much mandatory exercise groups
if (numberOfOptionalExercises < 0) {
throw new BadRequestAlertException("The number of mandatory exercise groups is too large", "Exam", "artemisApp.exam.validation.tooManyMandatoryExerciseGroups");
}
// Ensure that all exercises in an exercise group have the same meaning for the exam score calculation
for (ExerciseGroup exerciseGroup : exam.getExerciseGroups()) {
Set<IncludedInOverallScore> meaningsForScoreCalculation = exerciseGroup.getExercises().stream().map(Exercise::getIncludedInOverallScore).collect(Collectors.toSet());
if (meaningsForScoreCalculation.size() > 1) {
throw new BadRequestAlertException("All exercises in an exercise group must have the same meaning for the exam score", "Exam", "artemisApp.exam.validation.allExercisesInExerciseGroupOfSameIncludedType");
}
}
// Check that the exam max points is set
if (exam.getMaxPoints() == 0) {
throw new BadRequestAlertException("The exam max points can not be 0.", "Exam", "artemisApp.exam.validation.maxPointsNotSet");
}
// Ensure that all exercises in an exercise group have the same amount of max points and max bonus points
for (ExerciseGroup exerciseGroup : exam.getExerciseGroups()) {
Set<Double> allMaxPoints = exerciseGroup.getExercises().stream().map(Exercise::getMaxPoints).collect(Collectors.toSet());
Set<Double> allBonusPoints = exerciseGroup.getExercises().stream().map(Exercise::getBonusPoints).collect(Collectors.toSet());
if (allMaxPoints.size() > 1 || allBonusPoints.size() > 1) {
throw new BadRequestAlertException("All exercises in an exercise group need to give the same amount of points", "Exam", "artemisApp.exam.validation.allExercisesInExerciseGroupGiveSameNumberOfPoints");
}
}
// Ensure that the sum of all max points of mandatory exercise groups is not bigger than the max points set in the exam
// At this point we are already sure that each exercise group has at least one exercise, all exercises in the group have the same no of points
// and all are of the same calculation type, therefore we can just use any as representation for the group here
Double pointsReachableByMandatoryExercises = 0.0;
Set<ExerciseGroup> mandatoryExerciseGroups = exam.getExerciseGroups().stream().filter(ExerciseGroup::getIsMandatory).collect(Collectors.toSet());
for (ExerciseGroup exerciseGroup : mandatoryExerciseGroups) {
Exercise groupRepresentativeExercise = exerciseGroup.getExercises().stream().findAny().get();
if (groupRepresentativeExercise.getIncludedInOverallScore().equals(IncludedInOverallScore.INCLUDED_COMPLETELY)) {
pointsReachableByMandatoryExercises += groupRepresentativeExercise.getMaxPoints();
}
}
if (pointsReachableByMandatoryExercises > exam.getMaxPoints()) {
throw new BadRequestAlertException("Check that you set the exam max points correctly! The max points a student can earn in the mandatory exercise groups is too big", "Exam", "artemisApp.exam.validation.tooManyMaxPoints");
}
// Ensure that the sum of all max points of all exercise groups is at least as big as the max points set in the exam
Double pointsReachable = 0.0;
for (ExerciseGroup exerciseGroup : exam.getExerciseGroups()) {
Exercise groupRepresentativeExercise = exerciseGroup.getExercises().stream().findAny().get();
if (groupRepresentativeExercise.getIncludedInOverallScore().equals(IncludedInOverallScore.INCLUDED_COMPLETELY)) {
pointsReachable += groupRepresentativeExercise.getMaxPoints();
}
}
if (pointsReachable < exam.getMaxPoints()) {
throw new BadRequestAlertException("Check that you set the exam max points correctly! The max points a student can earn in the exercise groups is too low", "Exam", "artemisApp.exam.validation.tooFewMaxPoints");
}
}
use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ExamService method evaluateQuizExercises.
/**
* Evaluates all the quiz exercises of an exam
*
* @param examId id of the exam for which the quiz exercises should be evaluated
* @return number of evaluated exercises
*/
public Integer evaluateQuizExercises(Long examId) {
var exam = examRepository.findWithExerciseGroupsAndExercisesById(examId).orElseThrow(() -> new EntityNotFoundException("Exam", examId));
// Collect all quiz exercises for the given exam
Set<QuizExercise> quizExercises = new HashSet<>();
for (ExerciseGroup exerciseGroup : exam.getExerciseGroups()) {
for (Exercise exercise : exerciseGroup.getExercises()) {
if (exercise instanceof QuizExercise) {
quizExercises.add((QuizExercise) exercise);
}
}
}
long start = System.nanoTime();
log.info("Evaluating {} quiz exercises in exam {}", quizExercises.size(), examId);
// Evaluate all quizzes for that exercise
quizExercises.forEach(quiz -> examQuizService.evaluateQuizAndUpdateStatistics(quiz.getId()));
log.info("Evaluated {} quiz exercises in exam {} in {}", quizExercises.size(), examId, TimeLogUtil.formatDurationFrom(start));
return quizExercises.size();
}
Aggregations