Beispiel #1
0
    def post(self):
        if not current_app.config.get('DEMO_INSTALLATION', False):
            abort(404, title="Demo Accounts Unavailable", message="Sorry, the system settings do now allow the use of demo accounts.")

        params = new_user_demo_parser.parse_args()

        user = User()
        user.password = "******"

        system_role = params.get("system_role")
        check_valid_system_role(system_role)
        user.system_role = SystemRole(system_role)

        user_count = User.query \
            .filter_by(system_role=user.system_role) \
            .count()
        user_count += 1

        # username
        while True:
            if user.system_role == SystemRole.sys_admin:
                user.username="******"+str(user_count)
            elif user.system_role == SystemRole.instructor:
                user.username="******"+str(user_count)
            else:
                user.username="******"+str(user_count)

            username_exists = User.query.filter_by(username=user.username).first()
            if not username_exists:
                break
            else:
                user_count+=1

        if user.system_role == SystemRole.sys_admin:
            user.firstname = "Admin"
            user.lastname = str(user_count)
            user.displayname = "Admin "+str(user_count)
        elif user.system_role == SystemRole.instructor:
            user.firstname = "Instructor"
            user.lastname = str(user_count)
            user.displayname = "Instructor "+str(user_count)

            # create new enrollment
            new_user_course = UserCourse(
                user=user,
                course_id=1,
                course_role=CourseRole.instructor
            )
            db.session.add(new_user_course)
        else:
            user.firstname = "Student"
            user.lastname = str(user_count)
            user.displayname = display_name_generator()

            while True:
                user.student_number = random_generator(8, string.digits)
                student_number_exists = User.query.filter_by(student_number=user.student_number).first()
                if not student_number_exists:
                    break

            # create new enrollment
            new_user_course = UserCourse(
                user=user,
                course_id=1,
                course_role=CourseRole.student
            )
            db.session.add(new_user_course)

        try:
            db.session.add(user)
            db.session.commit()
            on_user_demo_create.send(
                self,
                event_name=on_user_demo_create.name,
                user=current_user,
                data=marshal(user, dataformat.get_full_user()))

        except exc.IntegrityError:
            db.session.rollback()
            current_app.logger.error("Failed to add new user. Duplicate.")
            return {'error': 'A user with the same identifier already exists.'}, 400

        authenticate(user, login_method="Demo")

        return marshal(user, dataformat.get_full_user())
Beispiel #2
0
    def post(self):
        # login_required when lti_create_user_link not set
        if not sess.get(
                'lti_create_user_link') and not current_user.is_authenticated:
            return current_app.login_manager.unauthorized()

        user = User()
        params = new_user_parser.parse_args()
        user.student_number = params.get("student_number", None)
        user.email = params.get("email")
        user.firstname = params.get("firstname")
        user.lastname = params.get("lastname")
        user.displayname = params.get("displayname")

        email_notification_method = params.get("email_notification_method")
        check_valid_email_notification_method(email_notification_method)
        user.email_notification_method = EmailNotificationMethod(
            email_notification_method)

        if not current_app.config.get('APP_LOGIN_ENABLED'):
            # if APP_LOGIN_ENABLED is not enabled, allow blank username and password
            user.username = None
            user.password = None
        else:
            # else enforce required password and unique username
            user.password = params.get("password")
            if user.password == None:
                abort(
                    400,
                    title="User Not Saved",
                    message=
                    "A password is required. Please enter a password and try saving again."
                )
            elif len(params.get("password")) < 4:
                abort(
                    400,
                    title="User Not Saved",
                    message="The password must be at least 4 characters long.")

            user.username = params.get("username")
            if user.username == None:
                abort(
                    400,
                    title="User Not Saved",
                    message=
                    "A username is required. Please enter a username and try saving again."
                )

            username_exists = User.query.filter_by(
                username=user.username).first()
            if username_exists:
                abort(
                    409,
                    title="User Not Saved",
                    message=
                    "Sorry, this username already exists and usernames must be unique in ComPAIR. Please enter another username and try saving again."
                )

        student_number_exists = User.query.filter_by(
            student_number=user.student_number).first()
        # if student_number is not left blank and it exists -> 409 error
        if user.student_number is not None and student_number_exists:
            abort(
                409,
                title="User Not Saved",
                message=
                "Sorry, this student number already exists and student numbers must be unique in ComPAIR. Please enter another number and try saving again."
            )

        # handle lti_create_user_link setup for third party logins
        if sess.get('lti_create_user_link') and sess.get('LTI'):
            lti_user = LTIUser.query.get_or_404(sess['lti_user'])
            lti_user.compair_user = user
            user.system_role = lti_user.system_role
            lti_user.update_user_profile()

            if sess.get('lti_context') and sess.get('lti_user_resource_link'):
                lti_context = LTIContext.query.get_or_404(sess['lti_context'])
                lti_user_resource_link = LTIUserResourceLink.query.get_or_404(
                    sess['lti_user_resource_link'])
                if lti_context.is_linked_to_course():
                    # create new enrollment
                    new_user_course = UserCourse(
                        user=user,
                        course_id=lti_context.compair_course_id,
                        course_role=lti_user_resource_link.course_role)
                    db.session.add(new_user_course)
        else:
            system_role = params.get("system_role")
            check_valid_system_role(system_role)
            user.system_role = SystemRole(system_role)

            require(
                CREATE,
                user,
                title="User Not Saved",
                message="Sorry, your role does not allow you to save users.")

        # only students can have student numbers
        if user.system_role != SystemRole.student:
            user.student_number = None

        try:
            db.session.add(user)
            db.session.commit()
            if current_user.is_authenticated:
                on_user_create.send(self,
                                    event_name=on_user_create.name,
                                    user=current_user,
                                    data=marshal(user,
                                                 dataformat.get_full_user()))
            else:
                on_user_create.send(self,
                                    event_name=on_user_create.name,
                                    data=marshal(user,
                                                 dataformat.get_full_user()))

        except exc.IntegrityError:
            db.session.rollback()
            current_app.logger.error("Failed to add new user. Duplicate.")
            abort(
                409,
                title="User Not Saved",
                message=
                "Sorry, this ID already exists and IDs must be unique in ComPAIR. Please try addding another user."
            )

        # handle lti_create_user_link teardown for third party logins
        if sess.get('lti_create_user_link'):
            authenticate(user, login_method='LTI')
            sess.pop('lti_create_user_link')

        return marshal_user_data(user)
Beispiel #3
0
def import_users(import_type, course, users):
    invalids = []  # invalid entries - eg. invalid # of columns
    count = 0  # store number of successful enrolments

    imported_users = []
    set_user_passwords = []

    # store unique user identifiers - eg. student number - throws error if duplicate in file
    import_usernames = []
    import_student_numbers = []

    # store unique user identifiers - eg. student number - throws error if duplicate in file
    existing_system_usernames = _get_existing_users_by_identifier(
        import_type, users)
    existing_system_student_numbers = _get_existing_users_by_student_number(
        import_type, users)

    groups = course.groups.all()
    groups_by_name = {}
    for group in groups:
        groups_by_name[group.name] = group

    # create / update users in file
    for user_row in users:
        if len(user_row) < 1:
            continue  # skip empty row
        user = _parse_user_row(import_type, user_row)

        # validate unique identifier
        username = user.get('username')
        password = user.get(
            'password'
        )  #always None for CAS/SAML import, can be None for existing users on ComPAIR import
        student_number = user.get('student_number')

        u = existing_system_usernames.get(username, None)

        if not username:
            invalids.append({
                'user': User(username=username),
                'message': 'The username is required.'
            })
            continue
        elif username in import_usernames:
            invalids.append({
                'user':
                User(username=username),
                'message':
                'This username already exists in the file.'
            })
            continue

        if u:
            # overwrite password if user has not logged in yet
            if u.last_online == None and not password in [None, '*']:
                set_user_passwords.append((u, password))
        else:
            u = User(username=None,
                     password=None,
                     student_number=user.get('student_number'),
                     firstname=user.get('firstname'),
                     lastname=user.get('lastname'),
                     email=user.get('email'))
            if import_type == ThirdPartyType.cas.value or import_type == ThirdPartyType.saml.value:
                # CAS/SAML login
                u.third_party_auths.append(
                    ThirdPartyUser(
                        unique_identifier=username,
                        third_party_type=ThirdPartyType(import_type)))
            else:
                # ComPAIR login
                u.username = username
                if password in [None, '*']:
                    invalids.append({
                        'user': u,
                        'message': 'The password is required.'
                    })
                    continue
                elif len(password) < 4:
                    invalids.append({
                        'user':
                        u,
                        'message':
                        'The password must be at least 4 characters long.'
                    })
                    continue
                else:
                    set_user_passwords.append((u, password))

            # validate student number (if not None)
            if student_number:
                # invalid if already showed up in file
                if student_number in import_student_numbers:
                    u.username = username
                    invalids.append({
                        'user':
                        u,
                        'message':
                        'This student number already exists in the file.'
                    })
                    continue
                # invalid if student number already exists in the system
                elif student_number in existing_system_student_numbers:
                    u.username = username
                    invalids.append({
                        'user':
                        u,
                        'message':
                        'This student number already exists in the system.'
                    })
                    continue

            u.system_role = SystemRole.student
            u.displayname = user.get('displayname') if user.get(
                'displayname') else display_name_generator()
            db.session.add(u)

        import_usernames.append(username)
        if student_number:
            import_student_numbers.append(student_number)
        imported_users.append((u, user.get('group')))
    db.session.commit()

    enroled = UserCourse.query \
        .filter_by(course_id=course.id) \
        .all()

    enroled = {e.user_id: e for e in enroled}

    students = UserCourse.query \
        .filter_by(
            course_id=course.id,
            course_role=CourseRole.student
        ) \
        .all()
    students = {s.user_id: s for s in students}

    # enrol valid users in file
    for user, group_name in imported_users:
        enrol = enroled.get(user.id,
                            UserCourse(course_id=course.id, user_id=user.id))
        enrol.group = None
        if group_name:
            group = groups_by_name.get(group_name)
            # add new groups if needed
            if not group:
                group = Group(course=course, name=group_name)
                groups_by_name[group_name] = group
                db.session.add(group)
            enrol.group = group

        # do not overwrite instructor or teaching assistant roles
        if enrol.course_role not in [
                CourseRole.instructor, CourseRole.teaching_assistant
        ]:
            enrol.course_role = CourseRole.student
            if user.id in students:
                del students[user.id]
            count += 1
        db.session.add(enrol)

    db.session.commit()

    # unenrol users not in file anymore
    for user_id in students:
        enrolment = students.get(user_id)
        # skip users that are already dropped
        if enrolment.course_role == CourseRole.dropped:
            continue
        enrolment.course_role = CourseRole.dropped
        enrolment.group_id = None
        db.session.add(enrolment)
    db.session.commit()

    # wait until user ids are generated before starting background jobs
    # perform password update in chunks of 100
    chunk_size = 100
    chunks = [
        set_user_passwords[index:index + chunk_size]
        for index in range(0, len(set_user_passwords), chunk_size)
    ]
    for chunk in chunks:
        set_passwords.delay({user.id: password for (user, password) in chunk})

    on_classlist_upload.send(current_app._get_current_object(),
                             event_name=on_classlist_upload.name,
                             user=current_user,
                             course_id=course.id)

    return {
        'success': count,
        'invalids': marshal(invalids,
                            dataformat.get_import_users_results(False))
    }
Beispiel #4
0
    def post(self):
        if not current_app.config.get('DEMO_INSTALLATION', False):
            abort(
                404,
                title="Demo Accounts Unavailable",
                message=
                "Sorry, the system settings do now allow the use of demo accounts."
            )

        params = new_user_demo_parser.parse_args()

        user = User()
        user.password = "******"

        system_role = params.get("system_role")
        check_valid_system_role(system_role)
        user.system_role = SystemRole(system_role)

        user_count = User.query \
            .filter_by(system_role=user.system_role) \
            .count()
        user_count += 1

        # username
        while True:
            if user.system_role == SystemRole.sys_admin:
                user.username = "******" + str(user_count)
            elif user.system_role == SystemRole.instructor:
                user.username = "******" + str(user_count)
            else:
                user.username = "******" + str(user_count)

            username_exists = User.query.filter_by(
                username=user.username).first()
            if not username_exists:
                break
            else:
                user_count += 1

        if user.system_role == SystemRole.sys_admin:
            user.firstname = "Admin"
            user.lastname = str(user_count)
            user.displayname = "Admin " + str(user_count)
        elif user.system_role == SystemRole.instructor:
            user.firstname = "Instructor"
            user.lastname = str(user_count)
            user.displayname = "Instructor " + str(user_count)

            # create new enrollment
            new_user_course = UserCourse(user=user,
                                         course_id=1,
                                         course_role=CourseRole.instructor)
            db.session.add(new_user_course)
        else:
            user.firstname = "Student"
            user.lastname = str(user_count)
            user.displayname = display_name_generator()

            while True:
                user.student_number = random_generator(8, string.digits)
                student_number_exists = User.query.filter_by(
                    student_number=user.student_number).first()
                if not student_number_exists:
                    break

            # create new enrollment
            new_user_course = UserCourse(user=user,
                                         course_id=1,
                                         course_role=CourseRole.student)
            db.session.add(new_user_course)

        try:
            db.session.add(user)
            db.session.commit()
            on_user_demo_create.send(self,
                                     event_name=on_user_demo_create.name,
                                     user=current_user,
                                     data=marshal(user,
                                                  dataformat.get_user(False)))

        except exc.IntegrityError:
            db.session.rollback()
            current_app.logger.error("Failed to add new user. Duplicate.")
            return {
                'error': 'A user with the same identifier already exists.'
            }, 400

        authenticate(user, login_method="Demo")

        return marshal(user, dataformat.get_user())
Beispiel #5
0
    def post(self):
        # login_required when lti_create_user_link not set
        if not sess.get('lti_create_user_link') and not current_user.is_authenticated:
            return current_app.login_manager.unauthorized()

        user = User()
        params = new_user_parser.parse_args()
        user.student_number = params.get("student_number", None)
        user.email = params.get("email")
        user.firstname = params.get("firstname")
        user.lastname = params.get("lastname")
        user.displayname = params.get("displayname")

        email_notification_method = params.get("email_notification_method")
        check_valid_email_notification_method(email_notification_method)
        user.email_notification_method = EmailNotificationMethod(email_notification_method)

        if not current_app.config.get('APP_LOGIN_ENABLED'):
            # if APP_LOGIN_ENABLED is not enabled, allow blank username and password
            user.username = None
            user.password = None
        else:
            # else enforce required password and unique username
            user.password = params.get("password")
            if user.password == None:
                abort(400, title="User Not Saved", message="A password is required. Please enter a password and try saving again.")
            elif len(params.get("password")) < 4:
                abort(400, title="User Not Saved", message="The password must be at least 4 characters long.")

            user.username = params.get("username")
            if user.username == None:
                abort(400, title="User Not Saved", message="A username is required. Please enter a username and try saving again.")

            username_exists = User.query.filter_by(username=user.username).first()
            if username_exists:
                abort(409, title="User Not Saved", message="Sorry, this username already exists and usernames must be unique in ComPAIR. Please enter another username and try saving again.")

        student_number_exists = User.query.filter_by(student_number=user.student_number).first()
        # if student_number is not left blank and it exists -> 409 error
        if user.student_number is not None and student_number_exists:
            abort(409, title="User Not Saved", message="Sorry, this student number already exists and student numbers must be unique in ComPAIR. Please enter another number and try saving again.")

        # handle lti_create_user_link setup for third party logins
        if sess.get('lti_create_user_link') and sess.get('LTI'):
            lti_user = LTIUser.query.get_or_404(sess['lti_user'])
            lti_user.compair_user = user
            user.system_role = lti_user.system_role
            lti_user.update_user_profile()

            if sess.get('lti_context') and sess.get('lti_user_resource_link'):
                lti_context = LTIContext.query.get_or_404(sess['lti_context'])
                lti_user_resource_link = LTIUserResourceLink.query.get_or_404(sess['lti_user_resource_link'])
                if lti_context.is_linked_to_course():
                    # create new enrollment
                    new_user_course = UserCourse(
                        user=user,
                        course_id=lti_context.compair_course_id,
                        course_role=lti_user_resource_link.course_role
                    )
                    db.session.add(new_user_course)
        else:
            system_role = params.get("system_role")
            check_valid_system_role(system_role)
            user.system_role = SystemRole(system_role)

            require(CREATE, user,
                title="User Not Saved",
                message="Sorry, your role does not allow you to save users.")

        # only students can have student numbers
        if user.system_role != SystemRole.student:
            user.student_number = None

        try:
            db.session.add(user)
            db.session.commit()
            if current_user.is_authenticated:
                on_user_create.send(
                    self,
                    event_name=on_user_create.name,
                    user=current_user,
                    data=marshal(user, dataformat.get_full_user()))
            else:
                on_user_create.send(
                    self,
                    event_name=on_user_create.name,
                    data=marshal(user, dataformat.get_full_user()))

        except exc.IntegrityError:
            db.session.rollback()
            current_app.logger.error("Failed to add new user. Duplicate.")
            abort(409, title="User Not Saved", message="Sorry, this ID already exists and IDs must be unique in ComPAIR. Please try addding another user.")

        # handle lti_create_user_link teardown for third party logins
        if sess.get('lti_create_user_link'):
            authenticate(user, login_method='LTI')
            sess.pop('lti_create_user_link')

        return marshal_user_data(user)
Beispiel #6
0
    def post(self):
        # login_required when oauth_create_user_link not set
        if not sess.get('oauth_create_user_link'):
            if not current_app.login_manager._login_disabled and \
                    not current_user.is_authenticated:
                return current_app.login_manager.unauthorized()

        user = User()
        params = new_user_parser.parse_args()
        user.student_number = params.get("student_number", None)
        user.email = params.get("email")
        user.firstname = params.get("firstname")
        user.lastname = params.get("lastname")
        user.displayname = params.get("displayname")

        email_notification_method = params.get("email_notification_method")
        check_valid_email_notification_method(email_notification_method)
        user.email_notification_method = EmailNotificationMethod(
            email_notification_method)

        # if creating a cas user, do not set username or password
        if sess.get('oauth_create_user_link') and sess.get('LTI') and sess.get(
                'CAS_CREATE'):
            user.username = None
            user.password = None
        else:
            # else enforce required password and unique username
            user.password = params.get("password")
            if user.password == None:
                abort(
                    400,
                    title="User Not Saved",
                    message=
                    "A password is required. Please enter a password and try saving again."
                )

            user.username = params.get("username")
            if user.username == None:
                abort(
                    400,
                    title="User Not Saved",
                    message=
                    "A username is required. Please enter a username and try saving again."
                )

            username_exists = User.query.filter_by(
                username=user.username).first()
            if username_exists:
                abort(
                    409,
                    title="User Not Saved",
                    message=
                    "Sorry, this username already exists and usernames must be unique in ComPAIR. Please enter another username and try saving again."
                )

        student_number_exists = User.query.filter_by(
            student_number=user.student_number).first()
        # if student_number is not left blank and it exists -> 409 error
        if user.student_number is not None and student_number_exists:
            abort(
                409,
                title="User Not Saved",
                message=
                "Sorry, this student number already exists and student numbers must be unique in ComPAIR. Please enter another number and try saving again."
            )

        # handle oauth_create_user_link setup for third party logins
        if sess.get('oauth_create_user_link'):
            login_method = None

            if sess.get('LTI'):
                lti_user = LTIUser.query.get_or_404(sess['lti_user'])
                lti_user.compair_user = user
                user.system_role = lti_user.system_role
                login_method = 'LTI'

                if sess.get('lti_context') and sess.get(
                        'lti_user_resource_link'):
                    lti_context = LTIContext.query.get_or_404(
                        sess['lti_context'])
                    lti_user_resource_link = LTIUserResourceLink.query.get_or_404(
                        sess['lti_user_resource_link'])
                    if lti_context.is_linked_to_course():
                        # create new enrollment
                        new_user_course = UserCourse(
                            user=user,
                            course_id=lti_context.compair_course_id,
                            course_role=lti_user_resource_link.course_role)
                        db.session.add(new_user_course)

                if sess.get('CAS_CREATE'):
                    thirdpartyuser = ThirdPartyUser(
                        third_party_type=ThirdPartyType.cas,
                        unique_identifier=sess.get('CAS_UNIQUE_IDENTIFIER'),
                        params=sess.get('CAS_PARAMS'),
                        user=user)
                    login_method = ThirdPartyType.cas.value
                    db.session.add(thirdpartyuser)
        else:
            system_role = params.get("system_role")
            check_valid_system_role(system_role)
            user.system_role = SystemRole(system_role)

            require(
                CREATE,
                user,
                title="User Not Saved",
                message="Sorry, your role does not allow you to save users.")

        # only students can have student numbers
        if user.system_role != SystemRole.student:
            user.student_number = None

        try:
            db.session.add(user)
            db.session.commit()
            if current_user.is_authenticated:
                on_user_create.send(self,
                                    event_name=on_user_create.name,
                                    user=current_user,
                                    data=marshal(user,
                                                 dataformat.get_user(False)))
            else:
                on_user_create.send(self,
                                    event_name=on_user_create.name,
                                    data=marshal(user,
                                                 dataformat.get_user(False)))

        except exc.IntegrityError:
            db.session.rollback()
            current_app.logger.error("Failed to add new user. Duplicate.")
            abort(
                409,
                title="User Not Saved",
                message=
                "Sorry, this ID already exists and IDs must be unique in ComPAIR. Please try addding another user."
            )

        # handle oauth_create_user_link teardown for third party logins
        if sess.get('oauth_create_user_link'):
            authenticate(user, login_method=login_method)
            sess.pop('oauth_create_user_link')

            if sess.get('CAS_CREATE'):
                sess.pop('CAS_CREATE')
                sess.pop('CAS_UNIQUE_IDENTIFIER')
                sess['CAS_LOGIN'] = True

        return marshal(user, dataformat.get_user())
Beispiel #7
0
def import_users(import_type, course, users):
    invalids = []  # invalid entries - eg. invalid # of columns
    count = 0  # store number of successful enrolments

    imported_users = []
    set_user_passwords = []

    # store unique user identifiers - eg. student number - throws error if duplicate in file
    import_usernames = []
    import_student_numbers = []

    # store unique user identifiers - eg. student number - throws error if duplicate in file
    existing_system_usernames = _get_existing_users_by_identifier(import_type, users)
    existing_system_student_numbers = _get_existing_users_by_student_number(import_type, users)

    groups = course.groups.all()
    groups_by_name = {}
    for group in groups:
        groups_by_name[group.name] = group

    # create / update users in file
    for user_row in users:
        if len(user_row) < 1:
            continue  # skip empty row
        user = _parse_user_row(import_type, user_row)

        # validate unique identifier
        username = user.get('username')
        password = user.get('password') #always None for CAS/SAML import, can be None for existing users on ComPAIR import
        student_number = user.get('student_number')

        u = existing_system_usernames.get(username, None)

        if not username:
            invalids.append({'user': User(username=username), 'message': 'The username is required.'})
            continue
        elif username in import_usernames:
            invalids.append({'user': User(username=username), 'message': 'This username already exists in the file.'})
            continue

        if u:
            # overwrite password if user has not logged in yet
            if u.last_online == None and not password in [None, '*']:
                set_user_passwords.append((u, password))
        else:
            u = User(
                username=None,
                password=None,
                student_number=user.get('student_number'),
                firstname=user.get('firstname'),
                lastname=user.get('lastname'),
                email=user.get('email')
            )
            if import_type == ThirdPartyType.cas.value or import_type == ThirdPartyType.saml.value:
                # CAS/SAML login
                u.third_party_auths.append(ThirdPartyUser(
                    unique_identifier=username,
                    third_party_type=ThirdPartyType(import_type)
                ))
            else:
                # ComPAIR login
                u.username = username
                if password in [None, '*']:
                    invalids.append({'user': u, 'message': 'The password is required.'})
                    continue
                elif len(password) < 4:
                    invalids.append({'user': u, 'message': 'The password must be at least 4 characters long.'})
                    continue
                else:
                    set_user_passwords.append((u, password))

            # validate student number (if not None)
            if student_number:
                # invalid if already showed up in file
                if student_number in import_student_numbers:
                    u.username = username
                    invalids.append({'user': u, 'message': 'This student number already exists in the file.'})
                    continue
                # invalid if student number already exists in the system
                elif student_number in existing_system_student_numbers:
                    u.username = username
                    invalids.append({'user': u, 'message': 'This student number already exists in the system.'})
                    continue

            u.system_role = SystemRole.student
            u.displayname = user.get('displayname') if user.get('displayname') else display_name_generator()
            db.session.add(u)

        import_usernames.append(username)
        if student_number:
            import_student_numbers.append(student_number)
        imported_users.append( (u, user.get('group')) )
    db.session.commit()

    enroled = UserCourse.query \
        .filter_by(course_id=course.id) \
        .all()

    enroled = {e.user_id: e for e in enroled}

    students = UserCourse.query \
        .filter_by(
            course_id=course.id,
            course_role=CourseRole.student
        ) \
        .all()
    students = {s.user_id: s for s in students}

    # enrol valid users in file
    for user, group_name in imported_users:
        enrol = enroled.get(user.id, UserCourse(course_id=course.id, user_id=user.id))
        enrol.group = None
        if group_name:
            group = groups_by_name.get(group_name)
            # add new groups if needed
            if not group:
                group = Group(
                    course=course,
                    name=group_name
                )
                groups_by_name[group_name] = group
                db.session.add(group)
            enrol.group = group

        # do not overwrite instructor or teaching assistant roles
        if enrol.course_role not in [CourseRole.instructor, CourseRole.teaching_assistant]:
            enrol.course_role = CourseRole.student
            if user.id in students:
                del students[user.id]
            count += 1
        db.session.add(enrol)

    db.session.commit()

    # unenrol users not in file anymore
    for user_id in students:
        enrolment = students.get(user_id)
        # skip users that are already dropped
        if enrolment.course_role == CourseRole.dropped:
            continue
        enrolment.course_role = CourseRole.dropped
        enrolment.group_id = None
        db.session.add(enrolment)
    db.session.commit()

    # wait until user ids are generated before starting background jobs
    # perform password update in chunks of 100
    chunk_size = 100
    chunks = [set_user_passwords[index:index + chunk_size] for index in range(0, len(set_user_passwords), chunk_size)]
    for chunk in chunks:
        set_passwords.delay({
            user.id: password for (user, password) in chunk
        })

    on_classlist_upload.send(
        current_app._get_current_object(),
        event_name=on_classlist_upload.name,
        user=current_user,
        course_id=course.id
    )

    return {
        'success': count,
        'invalids': marshal(invalids, dataformat.get_import_users_results(False))
    }
Beispiel #8
0
    def post(self):
        # login_required when oauth_create_user_link not set
        if not sess.get('oauth_create_user_link'):
            if not current_app.login_manager._login_disabled and \
                    not current_user.is_authenticated:
                return current_app.login_manager.unauthorized()

        user = User()
        params = new_user_parser.parse_args()
        user.student_number = params.get("student_number", None)
        user.email = params.get("email")
        user.firstname = params.get("firstname")
        user.lastname = params.get("lastname")
        user.displayname = params.get("displayname")

        # if creating a cas user, do not set username or password
        if sess.get('oauth_create_user_link') and sess.get('LTI') and sess.get('CAS_CREATE'):
            user.username = None
            user.password = None
        else:
            # else enforce required password and unique username
            user.password = params.get("password")
            if user.password == None:
                return {"error": "Missing required parameter: password."}, 400

            user.username = params.get("username")
            if user.username == None:
                return {"error": "Missing required parameter: username."}, 400

            username_exists = User.query.filter_by(username=user.username).first()
            if username_exists:
                return {"error": "This username already exists. Please pick another."}, 409

        student_number_exists = User.query.filter_by(student_number=user.student_number).first()
        # if student_number is not left blank and it exists -> 409 error
        if user.student_number is not None and student_number_exists:
            return {"error": "This student number already exists. Please pick another."}, 409

        # handle oauth_create_user_link setup for third party logins
        if sess.get('oauth_create_user_link'):
            login_method = None

            if sess.get('LTI'):
                lti_user = LTIUser.query.get_or_404(sess['lti_user'])
                lti_user.compair_user = user
                user.system_role = lti_user.system_role
                login_method = 'LTI'

                if sess.get('lti_context') and sess.get('lti_user_resource_link'):
                    lti_context = LTIContext.query.get_or_404(sess['lti_context'])
                    lti_user_resource_link = LTIUserResourceLink.query.get_or_404(sess['lti_user_resource_link'])
                    if lti_context.is_linked_to_course():
                        # create new enrollment
                        new_user_course = UserCourse(
                            user=user,
                            course_id=lti_context.compair_course_id,
                            course_role=lti_user_resource_link.course_role
                        )
                        db.session.add(new_user_course)

                if sess.get('CAS_CREATE'):
                    thirdpartyuser = ThirdPartyUser(
                        third_party_type=ThirdPartyType.cas,
                        unique_identifier=sess.get('CAS_UNIQUE_IDENTIFIER'),
                        params=sess.get('CAS_ADDITIONAL_PARAMS'),
                        user=user
                    )
                    login_method = ThirdPartyType.cas.value
                    db.session.add(thirdpartyuser)
        else:
            system_role = params.get("system_role")
            check_valid_system_role(system_role)
            user.system_role = SystemRole(system_role)

            require(CREATE, user)

        # only students can have student numbers
        if user.system_role != SystemRole.student:
            user.student_number = None

        try:
            db.session.add(user)
            db.session.commit()
            if current_user.is_authenticated:
                on_user_create.send(
                    self,
                    event_name=on_user_create.name,
                    user=current_user,
                    data=marshal(user, dataformat.get_user(False)))
            else:
                on_user_create.send(
                    self,
                    event_name=on_user_create.name,
                    data=marshal(user, dataformat.get_user(False)))

        except exc.IntegrityError:
            db.session.rollback()
            current_app.logger.error("Failed to add new user. Duplicate.")
            return {'error': 'A user with the same identifier already exists.'}, 400

        # handle oauth_create_user_link teardown for third party logins
        if sess.get('oauth_create_user_link'):
            authenticate(user, login_method=login_method)
            sess.pop('oauth_create_user_link')

            if sess.get('CAS_CREATE'):
                sess.pop('CAS_CREATE')
                sess.pop('CAS_UNIQUE_IDENTIFIER')
                sess['CAS_LOGIN'] = True

        return marshal(user, dataformat.get_user())