Search in sources :

Example 6 with StudentDTO

use of de.tum.in.www1.artemis.service.dto.StudentDTO 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;
}
Also used : StudentDTO(de.tum.in.www1.artemis.service.dto.StudentDTO) User(de.tum.in.www1.artemis.domain.User) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) AuditEvent(org.springframework.boot.actuate.audit.AuditEvent)

Example 7 with StudentDTO

use of de.tum.in.www1.artemis.service.dto.StudentDTO in project Artemis by ls1intum.

the class ExamResource method addStudentToExam.

/**
 * POST /courses/:courseId/exams/:examId/students/:studentLogin : Add one single given user (based on the login) to the students of the exam so that the student can access the exam
 *
 * @param courseId     the id of the course
 * @param examId       the id of the exam
 * @param studentLogin the login of the user who should get student access
 * @return empty ResponseEntity with status 200 (OK) or with status 404 (Not Found)
 */
@PostMapping(value = "/courses/{courseId}/exams/{examId}/students/{studentLogin:" + Constants.LOGIN_REGEX + "}")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<StudentDTO> addStudentToExam(@PathVariable Long courseId, @PathVariable Long examId, @PathVariable String studentLogin) {
    log.debug("REST request to add {} as student to exam : {}", studentLogin, examId);
    examAccessService.checkCourseAndExamAccessForInstructorElseThrow(courseId, examId);
    var course = courseRepository.findByIdElseThrow(courseId);
    var exam = examRepository.findByIdWithRegisteredUsersElseThrow(examId);
    var student = userRepository.findOneWithGroupsAndAuthoritiesByLogin(studentLogin).orElseThrow(() -> new EntityNotFoundException("User with login: \"" + studentLogin + "\" does not exist"));
    if (student.getGroups().contains(exam.getCourse().getInstructorGroupName()) || authCheckService.isAdmin(student)) {
        throw new AccessForbiddenException("You cannot register instructors or administrators to exams.");
    }
    examRegistrationService.registerStudentToExam(course, exam, student);
    var studentDto = new StudentDTO();
    studentDto.setRegistrationNumber(student.getRegistrationNumber());
    studentDto.setFirstName(student.getFirstName());
    studentDto.setLastName(student.getLastName());
    studentDto.setLogin(student.getLogin());
    return ResponseEntity.ok().body(studentDto);
}
Also used : StudentDTO(de.tum.in.www1.artemis.service.dto.StudentDTO) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) AccessForbiddenException(de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenException) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 8 with StudentDTO

use of de.tum.in.www1.artemis.service.dto.StudentDTO in project ArTEMiS by ls1intum.

the class ExamResource method addStudentToExam.

/**
 * POST /courses/:courseId/exams/:examId/students/:studentLogin : Add one single given user (based on the login) to the students of the exam so that the student can access the exam
 *
 * @param courseId     the id of the course
 * @param examId       the id of the exam
 * @param studentLogin the login of the user who should get student access
 * @return empty ResponseEntity with status 200 (OK) or with status 404 (Not Found)
 */
@PostMapping(value = "/courses/{courseId}/exams/{examId}/students/{studentLogin:" + Constants.LOGIN_REGEX + "}")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<StudentDTO> addStudentToExam(@PathVariable Long courseId, @PathVariable Long examId, @PathVariable String studentLogin) {
    log.debug("REST request to add {} as student to exam : {}", studentLogin, examId);
    examAccessService.checkCourseAndExamAccessForInstructorElseThrow(courseId, examId);
    var course = courseRepository.findByIdElseThrow(courseId);
    var exam = examRepository.findByIdWithRegisteredUsersElseThrow(examId);
    var student = userRepository.findOneWithGroupsAndAuthoritiesByLogin(studentLogin).orElseThrow(() -> new EntityNotFoundException("User with login: \"" + studentLogin + "\" does not exist"));
    if (student.getGroups().contains(exam.getCourse().getInstructorGroupName()) || authCheckService.isAdmin(student)) {
        throw new AccessForbiddenException("You cannot register instructors or administrators to exams.");
    }
    examRegistrationService.registerStudentToExam(course, exam, student);
    var studentDto = new StudentDTO();
    studentDto.setRegistrationNumber(student.getRegistrationNumber());
    studentDto.setFirstName(student.getFirstName());
    studentDto.setLastName(student.getLastName());
    studentDto.setLogin(student.getLogin());
    return ResponseEntity.ok().body(studentDto);
}
Also used : StudentDTO(de.tum.in.www1.artemis.service.dto.StudentDTO) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) AccessForbiddenException(de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenException) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 9 with StudentDTO

use of de.tum.in.www1.artemis.service.dto.StudentDTO in project ArTEMiS by ls1intum.

the class CourseService method registerUsersForCourseGroup.

/**
 * Add multiple users to the course so that they can access it
 * 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 user 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 studentDTOs   the list of students (with at least registration number)
 * @param courseGroup   the group the students should be added to
 * @return the list of students who could not be registered for the course, because they could NOT be found in the Artemis database and could NOT be found in the TUM LDAP
 */
public List<StudentDTO> registerUsersForCourseGroup(Long courseId, List<StudentDTO> studentDTOs, String courseGroup) {
    var course = courseRepository.findByIdElseThrow(courseId);
    String courseGroupName = course.defineCourseGroupName(courseGroup);
    Role courseGroupRole = Role.fromString(courseGroup);
    List<StudentDTO> notFoundStudentsDTOs = new ArrayList<>();
    for (var studentDto : studentDTOs) {
        var registrationNumber = studentDto.getRegistrationNumber();
        var login = studentDto.getLogin();
        Optional<User> optionalStudent = userService.findUserAndAddToCourse(registrationNumber, courseGroupName, courseGroupRole, login);
        if (optionalStudent.isEmpty()) {
            notFoundStudentsDTOs.add(studentDto);
        }
    }
    return notFoundStudentsDTOs;
}
Also used : Role(de.tum.in.www1.artemis.security.Role) StudentDTO(de.tum.in.www1.artemis.service.dto.StudentDTO)

Example 10 with StudentDTO

use of de.tum.in.www1.artemis.service.dto.StudentDTO in project Artemis by ls1intum.

the class ExamIntegrationTest method testRegisterUsersInExam.

@Test
@WithMockUser(username = "instructor1", roles = "INSTRUCTOR")
public void testRegisterUsersInExam() throws Exception {
    jiraRequestMockProvider.enableMockingOfRequests();
    var exam = ModelFactory.generateExam(course1);
    var savedExam = examRepository.save(exam);
    var student1 = database.getUserByLogin("student1");
    var student2 = database.getUserByLogin("student2");
    var student3 = database.getUserByLogin("student3");
    var student5 = database.getUserByLogin("student5");
    var student6 = database.getUserByLogin("student6");
    var student7 = database.getUserByLogin("student7");
    var student8 = database.getUserByLogin("student8");
    var student9 = database.getUserByLogin("student9");
    var student10 = database.getUserByLogin("student10");
    var registrationNumber1 = "1111111";
    var registrationNumber2 = "1111112";
    var registrationNumber3 = "1111113";
    var registrationNumber3WithTypo = registrationNumber3 + "0";
    var registrationNumber5 = "1111115";
    var registrationNumber5WithTypo = registrationNumber5 + "1";
    var registrationNumber6 = "1111116";
    var registrationNumber99 = "1111199";
    var registrationNumber100 = "1111100";
    var emptyRegistrationNumber = "";
    student1.setRegistrationNumber(registrationNumber1);
    student2.setRegistrationNumber(registrationNumber2);
    student3.setRegistrationNumber(registrationNumber3);
    student5.setRegistrationNumber(registrationNumber5);
    student6.setRegistrationNumber(registrationNumber6);
    student7.setRegistrationNumber(null);
    student8.setRegistrationNumber("");
    student9.setRegistrationNumber(" ");
    student10.setRegistrationNumber(null);
    student1 = userRepo.save(student1);
    student2 = userRepo.save(student2);
    userRepo.save(student3);
    userRepo.save(student5);
    userRepo.save(student6);
    userRepo.save(student7);
    userRepo.save(student8);
    userRepo.save(student9);
    userRepo.save(student10);
    // mock the ldap service
    doReturn(Optional.empty()).when(ldapUserService).findByRegistrationNumber(registrationNumber3WithTypo);
    doReturn(Optional.empty()).when(ldapUserService).findByRegistrationNumber(emptyRegistrationNumber);
    doReturn(Optional.empty()).when(ldapUserService).findByRegistrationNumber(registrationNumber5WithTypo);
    var ldapUser100Dto = new LdapUserDto().registrationNumber(registrationNumber100).firstName("Student100").lastName("Student100").username("student100").email("student100@tum.de");
    doReturn(Optional.of(ldapUser100Dto)).when(ldapUserService).findByRegistrationNumber(registrationNumber100);
    // first and second mocked calls are expected to add student 5 and 99 to the course students
    jiraRequestMockProvider.mockAddUserToGroup(course1.getStudentGroupName(), false);
    jiraRequestMockProvider.mockAddUserToGroup(course1.getStudentGroupName(), false);
    // third mocked call expected to create student 100
    jiraRequestMockProvider.mockCreateUserInExternalUserManagement(ldapUser100Dto.getUsername(), ldapUser100Dto.getFirstName() + " " + ldapUser100Dto.getLastName(), ldapUser100Dto.getEmail());
    // the last two mocked calls are expected to add students 100, 6, 7, 8, and 9 to the course student group
    for (int i = 0; i < 5; i++) {
        jiraRequestMockProvider.mockAddUserToGroup(course1.getStudentGroupName(), false);
    }
    bitbucketRequestMockProvider.mockUpdateUserDetails(student5.getLogin(), student5.getEmail(), student5.getName());
    bitbucketRequestMockProvider.mockAddUserToGroups();
    // not registered for the course
    var student99 = ModelFactory.generateActivatedUser("student99");
    student99.setRegistrationNumber(registrationNumber99);
    userRepo.save(student99);
    bitbucketRequestMockProvider.mockUpdateUserDetails(student99.getLogin(), student99.getEmail(), student99.getName());
    bitbucketRequestMockProvider.mockAddUserToGroups();
    student99 = userRepo.findOneWithGroupsAndAuthoritiesByLogin("student99").get();
    assertThat(student99.getGroups()).doesNotContain(course1.getStudentGroupName());
    // Note: student100 is not yet a user of Artemis and should be retrieved from the LDAP
    request.postWithoutLocation("/api/courses/" + course1.getId() + "/exams/" + savedExam.getId() + "/students/student1", null, HttpStatus.OK, null);
    request.postWithoutLocation("/api/courses/" + course1.getId() + "/exams/" + savedExam.getId() + "/students/nonExistingStudent", null, HttpStatus.NOT_FOUND, null);
    Exam storedExam = examRepository.findWithRegisteredUsersById(savedExam.getId()).get();
    assertThat(storedExam.getRegisteredUsers()).containsExactly(student1);
    request.delete("/api/courses/" + course1.getId() + "/exams/" + savedExam.getId() + "/students/student1", HttpStatus.OK);
    request.delete("/api/courses/" + course1.getId() + "/exams/" + savedExam.getId() + "/students/nonExistingStudent", HttpStatus.NOT_FOUND);
    storedExam = examRepository.findWithRegisteredUsersById(savedExam.getId()).get();
    assertThat(storedExam.getRegisteredUsers()).isEmpty();
    var studentDto1 = new StudentDTO().registrationNumber(registrationNumber1);
    var studentDto2 = new StudentDTO().registrationNumber(registrationNumber2);
    // explicit typo, should be a registration failure later
    var studentDto3 = new StudentDTO().registrationNumber(registrationNumber3WithTypo);
    // explicit typo, should fall back to login name later
    var studentDto5 = new StudentDTO().registrationNumber(registrationNumber5WithTypo);
    studentDto5.setLogin(student5.getLogin());
    var studentDto7 = new StudentDTO();
    studentDto7.setLogin(student7.getLogin());
    var studentDto8 = new StudentDTO();
    studentDto8.setLogin(student8.getLogin());
    var studentDto9 = new StudentDTO();
    studentDto9.setLogin(student9.getLogin());
    // completely empty
    var studentDto10 = new StudentDTO();
    var studentDto99 = new StudentDTO().registrationNumber(registrationNumber99);
    var studentDto100 = new StudentDTO().registrationNumber(registrationNumber100);
    // Add a student with login but empty registration number
    var studentDto6 = new StudentDTO().registrationNumber(emptyRegistrationNumber);
    studentDto6.setLogin(student6.getLogin());
    var studentsToRegister = List.of(studentDto1, studentDto2, studentDto3, studentDto5, studentDto99, studentDto100, studentDto6, studentDto7, studentDto8, studentDto9, studentDto10);
    bitbucketRequestMockProvider.mockUpdateUserDetails("student100", "student100@tum.de", "Student100 Student100");
    bitbucketRequestMockProvider.mockAddUserToGroups();
    bitbucketRequestMockProvider.mockUpdateUserDetails(student6.getLogin(), student6.getEmail(), student6.getName());
    bitbucketRequestMockProvider.mockAddUserToGroups();
    bitbucketRequestMockProvider.mockUpdateUserDetails(student7.getLogin(), student7.getEmail(), student7.getName());
    bitbucketRequestMockProvider.mockAddUserToGroups();
    bitbucketRequestMockProvider.mockUpdateUserDetails(student8.getLogin(), student8.getEmail(), student8.getName());
    bitbucketRequestMockProvider.mockAddUserToGroups();
    bitbucketRequestMockProvider.mockUpdateUserDetails(student9.getLogin(), student9.getEmail(), student9.getName());
    bitbucketRequestMockProvider.mockAddUserToGroups();
    bitbucketRequestMockProvider.mockUpdateUserDetails(student10.getLogin(), student10.getEmail(), student10.getName());
    bitbucketRequestMockProvider.mockAddUserToGroups();
    bitbucketRequestMockProvider.mockUpdateUserDetails("student100", "student100@tum.de", "Student100 Student100");
    bitbucketRequestMockProvider.mockAddUserToGroups();
    // now we register all these students for the exam.
    List<StudentDTO> registrationFailures = request.postListWithResponseBody("/api/courses/" + course1.getId() + "/exams/" + savedExam.getId() + "/students", studentsToRegister, StudentDTO.class, HttpStatus.OK);
    assertThat(registrationFailures).containsExactlyInAnyOrder(studentDto3, studentDto10);
    storedExam = examRepository.findWithRegisteredUsersById(savedExam.getId()).get();
    // now a new user student100 should exist
    var student100 = database.getUserByLogin("student100");
    assertThat(storedExam.getRegisteredUsers()).containsExactlyInAnyOrder(student1, student2, student5, student99, student100, student6, student7, student8, student9);
    for (var user : storedExam.getRegisteredUsers()) {
        // all registered users must have access to the course
        user = userRepo.findOneWithGroupsAndAuthoritiesByLogin(user.getLogin()).get();
        assertThat(user.getGroups()).contains(course1.getStudentGroupName());
    }
    // Make sure delete also works if so many objects have been created before
    request.delete("/api/courses/" + course1.getId() + "/exams/" + savedExam.getId(), HttpStatus.OK);
}
Also used : StudentDTO(de.tum.in.www1.artemis.service.dto.StudentDTO) LdapUserDto(de.tum.in.www1.artemis.service.ldap.LdapUserDto) StudentExam(de.tum.in.www1.artemis.domain.exam.StudentExam) Exam(de.tum.in.www1.artemis.domain.exam.Exam) WithMockUser(org.springframework.security.test.context.support.WithMockUser) Test(org.junit.jupiter.api.Test)

Aggregations

StudentDTO (de.tum.in.www1.artemis.service.dto.StudentDTO)10 Exam (de.tum.in.www1.artemis.domain.exam.Exam)4 StudentExam (de.tum.in.www1.artemis.domain.exam.StudentExam)4 EntityNotFoundException (de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException)4 User (de.tum.in.www1.artemis.domain.User)2 Role (de.tum.in.www1.artemis.security.Role)2 LdapUserDto (de.tum.in.www1.artemis.service.ldap.LdapUserDto)2 AccessForbiddenException (de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenException)2 Test (org.junit.jupiter.api.Test)2 AuditEvent (org.springframework.boot.actuate.audit.AuditEvent)2 PreAuthorize (org.springframework.security.access.prepost.PreAuthorize)2 WithMockUser (org.springframework.security.test.context.support.WithMockUser)2