def add_to_section(request):
    try:
        canvas_course_id = request.LTI['custom_canvas_course_id']
        post_data = json.loads(request.body)
        section_id = post_data['section_id']
        users_to_add = post_data['users_to_add']
    except KeyError:
        message = "Missing post parameters to add users to section_id %s" % request.body
        logger.exception(message)
        return JsonResponse({'success': False, 'message': message}, status=500)

    failed_users = []
    for user in users_to_add:
        try:
            canvas_api_enrollments.enroll_user_sections(
                SDK_CONTEXT,
                section_id,
                user['enrollment_user_id'],
                enrollment_type=user['enrollment_type'],
                enrollment_role_id=user['enrollment_role_id'],
                enrollment_enrollment_state='active'
            )
        except (KeyError, CanvasAPIError):
            logger.exception("Failed to add user to section %s %s", section_id, json.dumps(user))
            failed_users.append(user)
    canvas_api_helper_courses.delete_cache(canvas_course_id=canvas_course_id)
    canvas_api_helper_enrollments.delete_cache(canvas_course_id)
    canvas_api_helper_sections.delete_cache(canvas_course_id)
    canvas_api_helper_sections.delete_section_cache(section_id)

    return JsonResponse({
        'added': len(users_to_add) - len(failed_users),
        'failed': failed_users
    })
Example #2
0
def add_to_section(request):
    try:
        canvas_course_id = request.LTI['custom_canvas_course_id']
        post_data = json.loads(request.body)
        section_id = post_data['section_id']
        users_to_add = post_data['users_to_add']
    except KeyError:
        message = "Missing post parameters to add users to section_id %s" % request.body
        logger.exception(message)
        return JsonResponse({'success': False, 'message': message}, status=500)

    failed_users = []
    for user in users_to_add:
        try:
            canvas_api_enrollments.enroll_user_sections(
                SDK_CONTEXT,
                section_id,
                user['enrollment_user_id'],
                enrollment_type=user['enrollment_type'],
                enrollment_role_id=user['enrollment_role_id'],
                enrollment_enrollment_state='active'
            )
        except (KeyError, CanvasAPIError):
            logger.exception("Failed to add user to section %s %s", section_id, json.dumps(user))
            failed_users.append(user)
    canvas_api_helper_courses.delete_cache(canvas_course_id=canvas_course_id)
    canvas_api_helper_enrollments.delete_cache(canvas_course_id)
    canvas_api_helper_sections.delete_cache(canvas_course_id)
    canvas_api_helper_sections.delete_section_cache(section_id)

    return JsonResponse({
        'added': len(users_to_add) - len(failed_users),
        'failed': failed_users
    })
def edit_section(request, section_id):
    canvas_course_id = request.LTI['custom_canvas_course_id']
    section_name = request.POST.get('section_name_input', '').strip()
    enrollment_count = request.POST.get('enrollment_count')

    # check to see if the textbox is empty
    if not section_name:
        return render(request, 'manage_sections/create_section_form.html', {}, status=400)

    # grab the section
    try:
        section = canvas_api_helper_sections.get_section(canvas_course_id, section_id)
    except RuntimeError:
        logger.exception(
            'Unable to get section {} (course {}) from Canvas'.format(
                section_id, canvas_course_id))
        section = None
    if not section:
        message = 'Failed to retrieve section {} from course {}'.format(section_id, canvas_course_id)
        logger.error(message)
        return JsonResponse({'message': message}, status=500)

    # verify we should allow the edit
    if not is_editable_section(section):
        # send http status code 422=Unprocessable Entity
        return JsonResponse(
            {'message': 'Error: Registrar fed sections cannot be edited'},
            status=422
        )

    # do the edit
    try:
        course_section = canvas_api_helper_sections.update_section(
            canvas_course_id, section_id, course_section_name=section_name
        )
    except RuntimeError:
        logger.exception('Unable to update section {} to {} on Canvas'.format(
            section, section_name))
        course_section = None
    else:
        canvas_api_helper_courses.delete_cache(canvas_course_id=canvas_course_id)
        canvas_api_helper_enrollments.delete_cache(canvas_course_id)

    # if section update failed for whatever reason, return error status.
    if not course_section:
        return render(request, 'manage_sections/create_section_form.html', {},
                      status=500)

    # Append section count to course_section object so the badge will appear
    # correctly. Setting to zero for newly created section.
    course_section['enrollment_count'] = enrollment_count or 0

    return render(request, 'manage_sections/section_list.html',
                  {'section': course_section})
Example #4
0
def edit_section(request, section_id):
    canvas_course_id = request.LTI['custom_canvas_course_id']
    section_name = request.POST.get('section_name_input', '').strip()
    enrollment_count = request.POST.get('enrollment_count')

    # check to see if the textbox is empty
    if not section_name:
        return render(request, 'manage_sections/create_section_form.html', {}, status=400)

    # grab the section
    try:
        section = canvas_api_helper_sections.get_section(canvas_course_id, section_id)
    except RuntimeError:
        logger.exception(
            'Unable to get section {} (course {}) from Canvas'.format(
                section_id, canvas_course_id))
        section = None
    if not section:
        message = 'Failed to retrieve section {} from course {}'.format(section_id, canvas_course_id)
        logger.error(message)
        return JsonResponse({'message': message}, status=500)

    # verify we should allow the edit
    if not is_editable_section(section):
        # send http status code 422=Unprocessable Entity
        return JsonResponse(
            {'message': 'Error: Registrar fed sections cannot be edited'},
            status=422
        )

    # do the edit
    try:
        course_section = canvas_api_helper_sections.update_section(
            canvas_course_id, section_id, course_section_name=section_name
        )
    except RuntimeError:
        logger.exception('Unable to update section {} to {} on Canvas'.format(
            section, section_name))
        course_section = None
    else:
        canvas_api_helper_courses.delete_cache(canvas_course_id=canvas_course_id)
        canvas_api_helper_enrollments.delete_cache(canvas_course_id)

    # if section update failed for whatever reason, return error status.
    if not course_section:
        return render(request, 'manage_sections/create_section_form.html', {},
                      status=500)

    # Append section count to course_section object so the badge will appear
    # correctly. Setting to zero for newly created section.
    course_section['enrollment_count'] = enrollment_count or 0

    return render(request, 'manage_sections/section_list.html',
                  {'section': course_section})
def remove_from_section(request):
    canvas_course_id = request.LTI['custom_canvas_course_id']
    user_section_id = request.POST.get('user_section_id')
    if not user_section_id:
        return JsonResponse({'message': "Invalid user_section_id %s" % user_section_id}, status=500)
    try:
        response = canvas_api_enrollments.conclude_enrollment(
            SDK_CONTEXT, canvas_course_id, user_section_id, 'delete'
        )
        canvas_api_helper_courses.delete_cache(canvas_course_id=canvas_course_id)
        canvas_api_helper_enrollments.delete_cache(canvas_course_id)
        canvas_api_helper_sections.delete_cache(canvas_course_id)
    except CanvasAPIError:
        message = "Failed to remove user from section %s in course %s", user_section_id, canvas_course_id
        logger.exception(message)
        return JsonResponse({'message': message}, status=500)

    return JsonResponse(response.json())
Example #6
0
def remove_from_section(request):
    canvas_course_id = request.LTI['custom_canvas_course_id']
    user_section_id = request.POST.get('user_section_id')
    section_id = request.POST.get('section_id')
    if not user_section_id:
        return JsonResponse({'message': "Invalid user_section_id %s" % user_section_id}, status=500)
    try:
        response = canvas_api_enrollments.conclude_enrollment(
            SDK_CONTEXT, canvas_course_id, user_section_id, 'delete'
        )
        canvas_api_helper_courses.delete_cache(canvas_course_id=canvas_course_id)
        canvas_api_helper_enrollments.delete_cache(canvas_course_id)
        canvas_api_helper_sections.delete_cache(canvas_course_id)
        canvas_api_helper_sections.delete_section_cache(section_id)

    except CanvasAPIError:
        message = "Failed to remove user from section %s in course %s", user_section_id, canvas_course_id
        logger.exception(message)
        canvas_api_helper_sections.delete_cache(canvas_course_id)
        return JsonResponse({'message': message}, status=500)

    return JsonResponse(response.json())
def remove_user(request):
    canvas_course_id = request.POST.get('canvas_course_id')
    sis_user_id = request.POST.get('sis_user_id')
    canvas_role_id = request.POST.get('canvas_role_id')
    user_role_id = request.POST.get('user_role_id')
    try:
        course_instance_id = request.LTI['lis_course_offering_sourcedid']
    except KeyError as e:
        return lti_key_error_response(request, e)

    user_role = get_user_role_if_permitted(course_instance_id, user_role_id)
    if user_role is None:
        return JsonResponse(
            {'result': 'failure',
             'message': 'Error: The specified user role {} is not valid.'
                 .format(user_role_id)},
            status=500)

    if int(user_role.canvas_role_id) != int(canvas_role_id):
        logger.exception(
            u'The specified Canvas role %s does not correspond with user role '
            u'%s record\'s Canvas role (%s).', canvas_role_id, user_role_id,
            user_role.canvas_role_id)
        return JsonResponse(
            {'result': 'failure',
             'message': 'Error: The specified canvas role {} is not valid.'
                 .format(canvas_role_id)},
            status=500)

    # start by getting all the enrollments for this user
    user_id = 'sis_user_id:%s' % sis_user_id
    try:
        user_enrollments = get_all_list_data(
                SDK_CONTEXT, enrollments.list_enrollments_users, user_id)
    except CanvasAPIError as api_error:
        logger.exception(
            u"CanvasAPIError trying to get enrollments for user %s",
            sis_user_id, api_error)
        return JsonResponse(
            {'result': 'failure',
             'message': 'Error: There was a problem getting enrollments for '
                        'the user.'},
            status=500)
    else:
        # create a filtered list of just the users enrollments for the course
        # matching the canvas_course_id and the canvas role being removed
        user_enrollments_to_remove = [
            enrollment['id'] for enrollment in user_enrollments
                if (int(enrollment['course_id']) == int(canvas_course_id)
                    and int(enrollment['role_id']) == int(canvas_role_id))]

    # Remove the user from all Canvas sections in course
    for enrollment_id in user_enrollments_to_remove:
        try:
            enrollments.conclude_enrollment(SDK_CONTEXT, canvas_course_id,
                                            enrollment_id, task='delete')
        except CanvasAPIError as api_error:
            logger.exception(
                u'Canvas API Error trying to delete user %s with enrollment id '
                u'%s from course instance %s: %s',
                sis_user_id, enrollment_id, course_instance_id, api_error
            )
            return JsonResponse(
                {'result': 'failure',
                 'message': 'Error: There was a problem in deleting the user'},
                status=500)

    # update canvas api caches
    canvas_api_helper_courses.delete_cache(canvas_course_id=canvas_course_id)
    canvas_api_helper_enrollments.delete_cache(canvas_course_id)
    canvas_api_helper_sections.delete_cache(canvas_course_id)

    logger.debug(
        u'Now removing user with user_id=%s from course_instance_id=%s in '
        u'CourseManager DB.',
        sis_user_id, course_instance_id
    )

    # find the enrollment in question
    model_class = get_course_member_class(user_role)
    try:
        enrollment = model_class.objects.get(
                         course_instance_id=course_instance_id,
                         user_id=sis_user_id)
    except model_class.DoesNotExist:
        logger.exception(u'Unable to remove user %s from %s membership in '
                         u'course %s: no such membership exists.', sis_user_id,
                         model_class._meta.db_table, course_instance_id)
        return JsonResponse(
            {'result': 'failure',
             'message': 'Error: There was a problem in deleting the user'},
            status=500)

    # now delete it
    try:
        enrollment.delete()
    except Exception as e:
        logger.exception(
            u"Error in deleting user=%s from course_instance_id=%s: %s",
            sis_user_id, course_instance_id, e.message
        )
        return JsonResponse(
            {'result': 'failure',
             'message': 'Error: There was a problem in deleting the user'},
            status=500)

    # Record the delete in the audit log
    audit_logger.info(
        u'Course Enrollee=%s was deleted by user=%s for canvas_course_id=%s',
        sis_user_id, request.user.username, canvas_course_id)

    response_data = {
        'result': 'success',
        'message': 'User successfully removed from course',
    }
    return JsonResponse(response_data)
def add_member_to_course(user_id, user_role_id, course_instance_id,
                         canvas_course_id):
    """
    Returns a (existing_enrollment, person) tuple, existing_enrollment is true
    if there was already an existing enrollment for the given user/role
    """

    user_role = get_user_role_if_permitted(course_instance_id, user_role_id)
    if user_role is None:
        return False, None

    # get an instance of the correct Course* model class for this role
    model_class = get_course_member_class(user_role)
    enrollment = model_class()

    # populate and store the enrollment in coursemanager
    enrollment.user_id = user_id
    enrollment.role_id = user_role_id
    enrollment.course_instance_id = course_instance_id
    logger.debug(u'Adding %s to %s table as user_role_id %s',
                 user_id, enrollment._meta.db_table, user_role_id)
    existing_enrollment = False
    try:
        enrollment.save()
    except IntegrityError as e:
        existing_enrollment = True
        logger.exception(u'Unable to save user %s to table %s as user_role_id '
                         u"%s.  It's possible the user is already enrolled.",
                         user_id, enrollment._meta.db_table, user_role_id)
    except RuntimeError as e:
        existing_enrollment = True
        logger.exception(u'Unexpected error while saving user %s to table %s '
                         u'as user_role_id %s.',
                         user_id, enrollment._meta.db_table, user_role_id)

    # get and annotate a Person instance for this enrollment
    person = Person.objects.filter(univ_id=user_id)[0]
    person.badge_label = get_badge_label_name(person.role_type_cd)
    person.role_id = user_role.role_id
    person.role_name = user_role.role_name

    # create the canvas enrollment if needed.  add enrollee to primary section
    # if it exists, otherwise add to the course.
    if not existing_enrollment:
        # TODO: both add_canvas_*_enrollee calls expect (and pass to the api)
        #       a role label.  the api docs show that as deprecated, and the
        #       preferred approach is to pass the role id.  we should do that.
        #       punted for now so we don't need to do another icommons_common
        #       release. Those helpers are used elsewhere, as well, so there are
        #       refactoring implications. We could use the SDK or the REST API
        #       in the future.
        canvas_role_name = get_canvas_role_name(user_role_id)
        canvas_section = get_canvas_course_section(course_instance_id)
        if canvas_section:
            canvas_enrollment = add_canvas_section_enrollee(
                canvas_section['id'], canvas_role_name, user_id, enrollment_role_id=user_role.canvas_role_id)
        else:
            canvas_enrollment = add_canvas_course_enrollee(
                canvas_course_id, canvas_role_name, user_id, enrollment_role_id=user_role.canvas_role_id)

        if canvas_enrollment:
            # flush the canvas api caches on successful enrollment
            canvas_api_helper_courses.delete_cache(
                canvas_course_id=canvas_course_id)
            canvas_api_helper_enrollments.delete_cache(canvas_course_id)
            canvas_api_helper_sections.delete_cache(canvas_course_id)
        else:
            logger.error(
                u'Unable to enroll %s as user_role_id %s (Canvas role id %s) '
                u'for course instance id %s.', user_id, user_role_id,
                user_role.canvas_role_id, course_instance_id)
    return existing_enrollment, person
def add_member_to_course(user_id, user_role_id, course_instance_id,
                         canvas_course_id):
    """
    Returns a (existing_enrollment, person) tuple, existing_enrollment is true
    if there was already an existing enrollment for the given user/role
    """
    # bail early if that's not a valid role
    try:
        user_role = UserRole.objects.get(role_id=user_role_id)
    except UserRole.DoesNotExist as e:
        logger.exception(u'user_role_id %s does not map to a valid user_role '
                         u'record.', user_role_id)
        return False, None

    # get an instance of the correct Course* model class for this role
    model_class = get_course_member_class(user_role)
    enrollment = model_class()

    # populate and store the enrollment in coursemanager
    enrollment.user_id = user_id
    enrollment.role_id = user_role_id
    enrollment.course_instance_id = course_instance_id
    logger.debug(u'Adding %s to %s table as user_role_id %s',
                 user_id, enrollment._meta.db_table, user_role_id)
    existing_enrollment = False
    try:
        enrollment.save()
    except IntegrityError as e:
        existing_enrollment = True
        logger.exception(u'Unable to save user %s to table %s as user_role_id '
                         u"%s.  It's possible the user is already enrolled.",
                         user_id, enrollment._meta.db_table, user_role_id)
    except RuntimeError as e:
        existing_enrollment = True
        logger.exception(u'Unexpected error while saving user %s to table %s '
                         u'as user_role_id %s.',
                         user_id, enrollment._meta.db_table, user_role_id)

    # get and annotate a Person instance for this enrollment
    person = Person.objects.filter(univ_id=user_id)[0]
    person.badge_label = get_badge_label_name(person.role_type_cd)
    person.role_name = user_role.role_name

    # create the canvas enrollment if needed.  add enrollee to primary section
    # if it exists, otherwise add to the course.
    if not existing_enrollment:
        try:
            mp_role = ManagePeopleRole.objects.get(user_role_id=user_role.role_id)
        except ManagePeopleRole.DoesNotExist:
            logger.exception(u"Unable to find user role id %s in the "
                             u'manage_people_role table to find its Canvas role '
                             u'name.', user_role_id)
        else:
            # TODO: both add_canvas_*_enrollee calls expect (and pass to the api)
            #       a role label.  the api docs show that as deprecated, and the
            #       preferred approach is to pass the role id.  we should do that.
            #       punted for now so we don't need to do another icommons_common
            #       release.
            canvas_section = get_canvas_course_section(course_instance_id)
            if canvas_section:
                canvas_enrollment = add_canvas_section_enrollee(
                                        canvas_section['id'],
                                        mp_role.canvas_role_label, user_id)
            else:
                canvas_enrollment = add_canvas_course_enrollee(
                                        canvas_course_id,
                                        mp_role.canvas_role_label, user_id)

            if canvas_enrollment:
                # flush the canvas api caches on successful enrollment
                canvas_api_helper_courses.delete_cache(
                    canvas_course_id=canvas_course_id)
                canvas_api_helper_enrollments.delete_cache(canvas_course_id)
                canvas_api_helper_sections.delete_cache(canvas_course_id)
            else:
                logger.error(u'Unable to enroll %s as user_role_id %s for course '
                             u'instance id %s.',
                             user_id, user_role_id, course_instance_id)
    return existing_enrollment, person
Example #10
0
def create_section_form(request):
    try:
        canvas_course_id = request.LTI['custom_canvas_course_id']
        course_instance_id = request.LTI['lis_course_offering_sourcedid']
        if course_instance_id == '' or course_instance_id is None:
            logger.error(
                'CID unavailable for course %s' % canvas_course_id
            )
            return render(request, 'manage_sections/error.html', status=500)
        sis_enrollment_section_list = []  # Sections fed from SIS
        section_list = []  # Sections not fed from SIS

        # fetch total_students_size for the course
        kwargs = {}
        kwargs['include'] = 'total_students'
        start = time.time()
        course = canvas_api_helper_courses.get_course(canvas_course_id, **kwargs)
        logger.debug('Total time for get_course is ={} for course {}'.format(time.time() - start, canvas_course_id))
        total_students_size = 0
        if course:
            if 'total_students' not in course:
                logger.debug('total_students not in cached object, flushing and refetching object..')
                # this is probably  a cached object without the count. Clear the cache object and re-fetch the course
                canvas_api_helper_courses.delete_cache(canvas_course_id=canvas_course_id)
                course = canvas_api_helper_courses.get_course(canvas_course_id, **kwargs)

            if course and 'total_students' in course:
                total_students_size = course['total_students']

        logger.debug('total_students_size={}'.format(total_students_size))


        # If the size > 300, due to performnace issues for larger courses,  do not fetch enrollments
        if total_students_size > 300:
            canvas_sections = canvas_api_helper_sections.get_sections(canvas_course_id, fetch_enrollments=False)
        else:
            canvas_sections = canvas_api_helper_sections.get_sections(canvas_course_id, fetch_enrollments=True)
        if not canvas_sections:
            logger.error(
                'No sections found for Canvas course %s' % canvas_course_id
            )
            return render(request, 'manage_sections/error.html', status=500)
        for section in canvas_sections:
            if 'enrollments' in section:
                section['enrollment_count'] = len(_filter_student_view_enrollments(section['enrollments']))
            else:
                section['enrollment_count'] = 'n/a'
            sis_section_id = section.get('sis_section_id')
            if sis_section_id == course_instance_id or sis_section_id == "ci:%s" % course_instance_id:
                # this matches the current course instance id and placed first on the list
                sis_enrollment_section_list.insert(0, section)
            elif is_enrollment_section(sis_section_id) or is_credit_status_section(sis_section_id):
                sis_enrollment_section_list.append(section)
            else:
                if is_sis_section(sis_section_id):
                    section['registrar_section_flag'] = True
                section_list.append(section)

        # case insensitive sort the sections in alpha order
        section_list = sorted(section_list, key=lambda x: x['name'].lower())

        return render(request, 'manage_sections/create_section_form.html', {
            'sections': section_list,
            'sisenrollmentsections': sis_enrollment_section_list
        })

    except Exception:
        logger.exception('Exception in create_section_form')
        return render(request, 'manage_sections/error.html', status=500)