Ejemplo n.º 1
0
 def _get_quizzes(context, course_id):
     quiz_list = get_all_list_data(context, quizzes.list_quizzes_in_course,
                                   course_id)
     for quiz in quiz_list:
         details = get_all_list_data(context,
                                     quiz_questions.list_questions_in_quiz,
                                     course_id=course_id,
                                     quiz_id=quiz['id'])
         quiz['questions'] = details
     return quiz_list
Ejemplo n.º 2
0
    def handle(self, *args, **options):
        term_id = options['term_id'][0]
        try:
            term = Term.objects.get(term_id=term_id)
        except Term.DoesNotExist:
            raise CommandError('Invalid term_id %d provided.' % term_id)
        logger.info("Creating Canvas user primary email report for term_id %d...", term_id)

        report_data = {}
        for ci in CourseInstance.objects.filter(term=term):
            if ci.canvas_course_id:
                logger.info("Retrieving users for canvas_course_id %d", ci.canvas_course_id)
                users = {}
                try:
                    users_with_email = get_all_list_data(
                        SDK_CONTEXT,
                        list_users_in_course_users,
                        ci.canvas_course_id,
                        'email'
                    )
                    for user in users_with_email:
                        user_id = user['sis_user_id']
                        if user_id not in users:
                            users[user_id] = {'email': user['email'], 'roles': []}

                    users_with_enrollments = get_all_list_data(
                        SDK_CONTEXT,
                        list_users_in_course_users,
                        ci.canvas_course_id,
                        'enrollments'
                    )
                    for user in users_with_enrollments:
                        users[user['sis_user_id']]['roles'].extend(
                            [enrollment['role'] for enrollment in user['enrollments']]
                        )
                except CanvasAPIError:
                    logger.exception("Failed to retrieve users for canvas_course_id %d", ci.canvas_course_id)
                    continue

                for p in Person.objects.filter(univ_id__in=list(users.keys())):
                    user = users[p.univ_id]
                    if p.email_address != user['email']:
                        for role in user['roles']:
                            if role not in report_data:
                                report_data[role] = []
                            report_data[role].append([role, p.univ_id, user['email']])

        report_path = os.path.join(settings.REPORT_DIR, 'report_user_primary_email.csv')
        with open(report_path, 'wb') as f:
            writer = csv.writer(f, dialect='excel')
            writer.writerow(['Role', 'SIS Email', 'Canvas Email'])
            for role, rows in report_data.items():
                writer.writerows(rows)

        logger.info("User primary email report complete for term_id %d at %s", term_id, report_path)
    def handle(self, *args, **options):
        term_id = options['term_id'][0]
        try:
            term = Term.objects.get(term_id=term_id)
        except Term.DoesNotExist:
            raise CommandError('Invalid term_id %d provided.' % term_id)
        logger.info("Creating Canvas user primary email report for term_id %d...", term_id)

        report_data = {}
        for ci in CourseInstance.objects.filter(term=term):
            if ci.canvas_course_id:
                logger.info("Retrieving users for canvas_course_id %d", ci.canvas_course_id)
                users = {}
                try:
                    users_with_email = get_all_list_data(
                        SDK_CONTEXT,
                        list_users_in_course_users,
                        ci.canvas_course_id,
                        'email'
                    )
                    for user in users_with_email:
                        user_id = user['sis_user_id']
                        if user_id not in users:
                            users[user_id] = {'email': user['email'], 'roles': []}

                    users_with_enrollments = get_all_list_data(
                        SDK_CONTEXT,
                        list_users_in_course_users,
                        ci.canvas_course_id,
                        'enrollments'
                    )
                    for user in users_with_enrollments:
                        users[user['sis_user_id']]['roles'].extend(
                            [enrollment['role'] for enrollment in user['enrollments']]
                        )
                except CanvasAPIError:
                    logger.exception("Failed to retrieve users for canvas_course_id %d", ci.canvas_course_id)
                    continue

                for p in Person.objects.filter(univ_id__in=users.keys()):
                    user = users[p.univ_id]
                    if p.email_address != user['email']:
                        for role in user['roles']:
                            if role not in report_data:
                                report_data[role] = []
                            report_data[role].append([role, p.univ_id, user['email']])

        report_path = os.path.join(settings.REPORT_DIR, 'report_user_primary_email.csv')
        with open(report_path, 'wb') as f:
            writer = csv.writer(f, dialect='excel')
            writer.writerow(['Role', 'SIS Email', 'Canvas Email'])
            for role, rows in report_data.iteritems():
                writer.writerows(rows)

        logger.info("User primary email report complete for term_id %d at %s", term_id, report_path)
Ejemplo n.º 4
0
    def test_get_all_list_data_calls_function_parameter_with_context_args_and_kwargs(self, mock_next):
        """
        Assert that call to get_all_list_data calls function parameter with context, args, and kwargs
        """
        mock_next.return_value = iter([])
        mock_function = mock.Mock(name='mock-function')
        arg1, arg2 = 'arg1', 'arg2'
        kwargs = {'kwarg1': 'val1', 'kwarg2': 'val2'}

        utils.get_all_list_data(self.req_ctx, mock_function, arg1, arg2, **kwargs)
        mock_function.assert_called_once_with(self.req_ctx, arg1, arg2, **kwargs)
Ejemplo n.º 5
0
    def test_get_all_list_data_calls_json_on_function_return_value(self, mock_next):
        """
        Assert that call to get_all_list_data makes call to json method on result of function call
        """
        mock_next.return_value = iter([])
        mock_function = mock.Mock(name='mock-function')
        mock_response = self.build_response_mock()
        mock_function.return_value = mock_response

        utils.get_all_list_data(self.req_ctx, mock_function)
        mock_response.json.assert_called_once_with()
Ejemplo n.º 6
0
    def test_get_all_list_data_calls_get_next_with_request_context_and_response(self, mock_next):
        """
        Assert that call to get_all_list_data makes a call to get_next with context and function response
        """
        mock_next.return_value = iter([])
        mock_function = mock.Mock(name='mock-function')
        mock_response = self.build_response_mock()
        mock_function.return_value = mock_response

        utils.get_all_list_data(self.req_ctx, mock_function)
        mock_next.assert_called_once_with(self.req_ctx, mock_response)
def get_administered_school_accounts(canvas_user_id,
                                     allowed_roles=ADMINISTRATOR_ROLES):
    cache_key = CACHE_KEY_ACCOUNTS_BY_USER.format(canvas_user_id)
    school_accounts = cache.get(cache_key)
    if school_accounts is None:

        # get all accounts
        all_canvas_accounts = get_all_list_data(
            SDK_CONTEXT,
            get_sub_accounts_of_account,
            settings.ICOMMONS_COMMON['CANVAS_ROOT_ACCOUNT_ID'],
            recursive=False)

        # filter so we only have the school accounts
        all_school_accounts = {
            a['id']: a
            for a in all_canvas_accounts
            if (a.get('sis_account_id') or '').startswith('school')
        }

        # retrieve accounts this user is directly associated with
        assigned_accounts = get_all_list_data(SDK_CONTEXT,
                                              list_accounts,
                                              as_user_id=canvas_user_id)

        # for some reason, the role they're assigned is under admins.  grab that
        # role for all the assigned accounts
        allowed_accounts = {}
        for account in assigned_accounts:
            admins = get_all_list_data(SDK_CONTEXT,
                                       list_account_admins,
                                       account['id'],
                                       user_id=canvas_user_id)

            if allowed_roles.intersection({a['role'] for a in admins}):
                allowed_accounts[account['id']] = account

        # if they're allowed on the root account, they're allowed everywhere
        if settings.ICOMMONS_COMMON[
                'CANVAS_ROOT_ACCOUNT_ID'] in allowed_accounts:
            school_accounts = all_school_accounts.values()
        else:
            # filter out the accounts where the user does not have the proper
            # permissions
            school_accounts = [
                acct for id_, acct in all_school_accounts.iteritems()
                if id_ in allowed_accounts
            ]

        logger.debug(u'%s has access to %s', canvas_user_id,
                     [a['sis_account_id'] for a in school_accounts])
        cache.set(cache_key, school_accounts)
    return school_accounts
Ejemplo n.º 8
0
    def test_get_all_list_data_raises_attribute_error_on_paged_results_if_initial_result_not_a_list(self, mock_next):
        """
        Assert that call to get_all_list_data will raise an AttributeError in the event that the initial response is something
        other than a list (i.e., a json string or dict)
        """
        # Simulate an initial response with 3 additional pages
        mock_next.return_value = iter([self.build_response_mock(json_data=["test-data"])])
        mock_function = mock.Mock(name="mock-function")
        mock_response = self.build_response_mock(json_data={"dict": "data"})
        mock_function.return_value = mock_response

        with self.assertRaises(AttributeError):
            utils.get_all_list_data(self.req_ctx, mock_function)
Ejemplo n.º 9
0
    def test_get_all_list_data_raises_attribute_error_on_paged_results_if_initial_result_not_a_list(self, mock_next):
        """
        Assert that call to get_all_list_data will raise an AttributeError in the event that the initial response is something
        other than a list (i.e., a json string or dict)
        """
        # Simulate an initial response with 3 additional pages
        mock_next.return_value = iter([
            self.build_response_mock(json_data=['test-data']),
        ])
        mock_function = mock.Mock(name='mock-function')
        mock_response = self.build_response_mock(json_data={'dict': 'data'})
        mock_function.return_value = mock_response

        with self.assertRaises(AttributeError):
            utils.get_all_list_data(self.req_ctx, mock_function)
Ejemplo n.º 10
0
 def _get_pages(context, course_id):
     page_list = get_all_list_data(context, pages.list_pages_courses,
                                   course_id)
     for page in page_list:
         details = pages.show_page_courses(context, course_id, page['url'])
         page['body'] = details.json()['body']
     return page_list
Ejemplo n.º 11
0
    def test_get_all_list_data_returns_concatenated_list_of_json_results(
            self, mock_next):
        """
        Assert that result of call to get_all_list_data is a single concatenated list of json data from
        series of "next" responses.
        """
        expected_json = [{
            'first': 'json'
        }, {
            'second': 'json'
        }, {
            'third': 'json'
        }, {
            'fourth': 'json'
        }]
        # Simulate an initial response with 3 additional pages
        mock_next.return_value = iter([
            self.build_response_mock(json_data=[expected_json[1]]),
            self.build_response_mock(json_data=[expected_json[2]]),
            self.build_response_mock(json_data=[expected_json[3]]),
        ])
        mock_function = mock.Mock(name='mock-function')
        mock_response = self.build_response_mock(json_data=[expected_json[0]])
        mock_function.return_value = mock_response

        results = utils.get_all_list_data(self.req_ctx, mock_function)
        self.assertEqual(
            results, expected_json,
            "The json list of data returned by get_all function should be the fully concatenated list of json"
        )
def get_canvas_site_templates_for_school(school_id):
    """
    Get the Canvas site templates for the given school. First check the cache, if not found construct
    the Canvas site template dictionairy list by querying CanvasSchoolTemplate and the courses Canvas API
    to get the Canvas template site name.

    :param school_id:
    :return: List of dicts containing data for Canvas site templates for the given school
    """
    cache_key = CACHE_KEY_CANVAS_SITE_TEMPLATES_BY_SCHOOL_ID % school_id
    templates = cache.get(cache_key)
    if templates is None:
        templates = []
        for t in CanvasSchoolTemplate.objects.filter(school_id=school_id):
            canvas_course_id = t.template_id
            course = get_all_list_data(
                SDK_CONTEXT,
                canvas_api_courses.get_single_course_courses,
                canvas_course_id,
                None
            )
            templates.append({
                'canvas_course_name': course['name'],
                'canvas_course_id': canvas_course_id,
                'canvas_course_url': "%s/courses/%d" % (settings.CANVAS_URL, canvas_course_id),
                'is_default': t.is_default
            })

        logger.debug("Caching canvas site templates for school_id %s %s", school_id, json.dumps(templates))
        cache.set(cache_key, templates)

    return templates
def api_get_students_list(request_context, course_id):
    '''
    Returns a list of all students in the course.
    
    https://canvas.instructure.com/doc/api/courses.html#method.courses.users
    '''
    logging.info("API fetching students for course: %s" % course_id)
    results = get_all_list_data(request_context,
                                courses.list_users_in_course_users,
                                course_id,
                                "email",
                                enrollment_type="student")

    # reduce the student data to the subset that we need
    students = [
        {
            "id": x['id'],  # canvas ID for user 
            "sis_user_id":
            x['sis_user_id'],  # huid from student information systems 
            "sortable_name": x['sortable_name'],
            "name": x['name'],
        } for x in results
    ]

    logging.debug("Students in course: %s" % students)

    return list(students)
def get_canvas_site_templates_for_school(school_id):
    """
    Get the Canvas site templates for the given school. First check the cache, if not found construct
    the Canvas site template dictionairy list by querying CanvasSchoolTemplate and the courses Canvas API
    to get the Canvas template site name.

    :param school_id:
    :return: List of dicts containing data for Canvas site templates for the given school
    """
    cache_key = CACHE_KEY_CANVAS_SITE_TEMPLATES_BY_SCHOOL_ID % school_id
    templates = cache.get(cache_key)
    if templates is None:
        templates = []
        for t in CanvasSchoolTemplate.objects.filter(school_id=school_id):
            canvas_course_id = t.template_id
            course = get_all_list_data(
                SDK_CONTEXT,
                canvas_api_courses.get_single_course_courses,
                canvas_course_id,
                None
            )
            templates.append({
                'canvas_course_name': course['name'],
                'canvas_course_id': canvas_course_id,
                'canvas_course_url': "%s/courses/%d" % (settings.CANVAS_URL, canvas_course_id),
                'is_default': t.is_default
            })

        logger.debug("Caching canvas site templates for school_id %s %s", school_id, json.dumps(templates))
        cache.set(cache_key, templates)

    return templates
def api_get_submissions(request_context, course_id, assignment_ids):
    '''
    Returns the submission data for each assignment.

    https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.index
    '''
    logging.info(
        "API fetching submissions for course %s and %d assignments (assignment_ids: %s)"
        %
        (course_id, len(assignment_ids), ', '.join(map(str, assignment_ids))))
    include = "assignment"
    results = []
    for position, assignment_id in enumerate(assignment_ids, start=1):
        logging.info(
            "[%d of %d] Fetching submissions for assignment_id: %d..." %
            (position, len(assignment_ids), assignment_id))
        list_data = get_all_list_data(
            request_context, submissions.list_assignment_submissions_courses,
            course_id, assignment_id, include)
        logging.debug("Submissions for assignment %s: %s" %
                      (assignment_id, list_data))
        results.append({
            "assignment_id": assignment_id,
            "submissions": list_data
        })
    return results
Ejemplo n.º 16
0
def _get_users_by_email(email_address, account_id=None, use_cache=True):
    if not email_address or not email_address.strip():
        return []

    if account_id is None:
        account_id = '1'  # account ID for root account in Canvas
    cache_key = CACHE_KEY_USER_IN_ACCOUNT_BY_SEARCH_TERM.format(account_id,
                                                                email_address)
    result = cache.get(cache_key) if use_cache else None
    if not result:
        kwargs = {'search_term': email_address, 'include': 'email'}
        try:
            result = get_all_list_data(
                SDK_CONTEXT,
                list_users_in_account,
                account_id,
                **kwargs)
        except CanvasAPIError:
            logger.error('Unable to lookup users in account {} for email '
                         'address {}'.format(account_id, email_address))
            raise
        logger.debug('Canvas user search results for account {} with search '
                     'term {}: {}'.format(account_id, email_address, result))
        if use_cache:
            cache.set(cache_key, result)
    return result
Ejemplo n.º 17
0
def _list_user_comm_channels(user_id, use_cache=False):
    """
    Note: we don't want to cache by default because we want to immediately
    pick up changes in user communication channels if they change them, e.g.
    if they're notified they need to update their communication channels and
    they attempt to email a list immediately afterwards, we want to pick up
    that change. Caching can still be done at the level of the mailgun route
    handler event trigger.
    """
    if not user_id:
        return []

    cache_key = CACHE_KEY_COMM_CHANNELS_BY_CANVAS_USER_ID % user_id
    result = cache.get(cache_key) if use_cache else None
    if not result:
        kwargs = {'user_id': user_id}
        try:
            result = get_all_list_data(
                SDK_CONTEXT,
                communication_channels.list_user_communication_channels,
                **kwargs)
        except CanvasAPIError:
            logger.error('Unable to get communication channels for '
                         'Canvas user {}'.format(user_id))
            raise
        logger.debug('Canvas communication channel results for user {}: '
                     '{}'.format(user_id, result))
        if use_cache:
            cache.set(cache_key, result)
    return result
Ejemplo n.º 18
0
def get_canvas_courses(account_id=None,
                       term_id=None,
                       search_term=None,
                       state=None):
    """Returns a list of active courses for the given account and term"""
    try:
        canvas_courses = get_all_list_data(
            SDK_CONTEXT,
            list_active_courses_in_account,
            account_id=account_id,
            enrollment_term_id=term_id,
            search_term=search_term,
            state=state,
        )

        total_count = len(canvas_courses)
        logger.info('Found %d courses' % total_count)

    except Exception as e:
        message = 'Error listing active courses in account'
        if isinstance(e, CanvasAPIError):
            message += ', SDK error details={}'.format(e)
        logger.exception(message)
        raise e

    return canvas_courses
def get_course_list_from_canvas(account_id):
    """
    Get a list of all the active courses for the give account_id.
    """
    course_list = get_all_list_data(SDK_CONTEXT, accounts.list_active_courses_in_account,
                                    account_id, with_enrollments=True)
    return course_list
def get_enrolled_roles_for_user_ids(canvas_course_id, search_results_user_ids):
    """
    Look for any ids returned from the search query that match ids already
    enrolled in the course.  If we find a match, add them to the found_ids.
    This list will be used in the template to disable the checkbox for ids that
    are already enrolled in the course and to display Canvas role names.
    Do not match XIDs.
    """
    canvas_enrollments = get_all_list_data(
            SDK_CONTEXT, enrollments.list_enrollments_courses, canvas_course_id)

    # get the updated (or cached) Canvas role list so we can show the right
    # role labels for these enrollments
    canvas_roles_by_role_id = get_roles_for_account_id('self')

    found_ids = defaultdict(list)
    for enrollment in canvas_enrollments:
        try:
            sis_user_id = enrollment['user']['sis_user_id']
        except KeyError:
            continue
        else:
            if sis_user_id in search_results_user_ids:
                enrollment.update(
                    {'canvas_role_label': canvas_roles_by_role_id[
                        enrollment['role_id']]['label']})
                found_ids[sis_user_id].append(enrollment)
    return found_ids
Ejemplo n.º 21
0
def get_assignments_list(request_context, course_id):
    """
    Returns a list of assignments for the course.
    https://canvas.instructure.com/doc/api/assignments.html#method.assignments_api.index 
    """

    results = get_all_list_data(request_context, assignments.list_assignments,
                                course_id, "")
    return list(filter(lambda x: "rubric" in x, results))
def get_course_list_from_canvas(account_id):
    """
    Get a list of all the active courses for the give account_id.
    """
    course_list = get_all_list_data(SDK_CONTEXT,
                                    accounts.list_active_courses_in_account,
                                    account_id,
                                    with_enrollments=True)
    return course_list
def get_administered_school_accounts(canvas_user_id, allowed_roles=ADMINISTRATOR_ROLES):
    cache_key = CACHE_KEY_ACCOUNTS_BY_USER.format(canvas_user_id)
    school_accounts = cache.get(cache_key)
    if school_accounts is None:

        # get all accounts
        all_canvas_accounts = get_all_list_data(
            SDK_CONTEXT,
            get_sub_accounts_of_account,
            settings.ICOMMONS_COMMON['CANVAS_ROOT_ACCOUNT_ID'],
            recursive=True)

        # filter so we only have the school accounts
        all_school_accounts = {a['id']: a for a in all_canvas_accounts
                               if (a.get('sis_account_id') or '').startswith('school')}

        # retrieve accounts this user is directly associated with
        assigned_accounts = get_all_list_data(SDK_CONTEXT, list_accounts,
                                              as_user_id=canvas_user_id)

        # for some reason, the role they're assigned is under admins.  grab that
        # role for all the assigned accounts
        allowed_accounts = {}
        for account in assigned_accounts:
            admins = get_all_list_data(SDK_CONTEXT, list_account_admins,
                                       account['id'], user_id=canvas_user_id)

            if allowed_roles.intersection({a['role'] for a in admins}):
                allowed_accounts[account['id']] = account

        # if they're allowed on the root account, they're allowed everywhere
        if settings.ICOMMONS_COMMON['CANVAS_ROOT_ACCOUNT_ID'] in allowed_accounts:
            school_accounts = all_school_accounts.values()
        else:
            # filter out the accounts where the user does not have the proper
            # permissions
            school_accounts = [acct for id_, acct in all_school_accounts.iteritems()
                                   if id_ in allowed_accounts]

        logger.debug(u'%s has access to %s', canvas_user_id,
                     [a['sis_account_id'] for a in school_accounts])
        cache.set(cache_key, school_accounts)
    return school_accounts
def api_get_assignments_list(request_context, course_id):
    '''
    Returns a list of assignments for the course.

    https://canvas.instructure.com/doc/api/assignments.html#method.assignments_api.index 
    '''
    logging.info("API fetching assignments for course: %s" % course_id)
    results = get_all_list_data(request_context, assignments.list_assignments,
                                course_id, '')
    logging.debug("Assignments List: %s" % [r['id'] for r in results])
    return results
def get_enrollments_from_canvas_section(canvas_section_id):
    """
    get the list of enrollments for the canvas section
    """
    enrollment_list = get_all_list_data(SDK_CONTEXT, enrollments.list_enrollments_sections, canvas_section_id)
    sis_user_id_list = []
    for enrollment in enrollment_list:
        sis_user_id = enrollment['user'].get('sis_user_id')
        if sis_user_id:
            sis_user_id_list.append(sis_user_id)
    return sis_user_id_list
Ejemplo n.º 26
0
def get_assignments_list(request_context, course_id):
    '''
    Returns a list of assignments for the course.
    https://canvas.instructure.com/doc/api/assignments.html#method.assignments_api.index 
    '''

    keys = ('id', 'name', 'due_at', 'rubric', 'rubric_settings'
            )  # reduce the clutter
    results = get_all_list_data(request_context, assignments.list_assignments,
                                course_id, '')
    my_assignments = list(filter(lambda x: 'rubric' in x, results))
    return [{k: assignment[k] for k in keys} for assignment in my_assignments]
def get_enrollments_from_canvas_section(canvas_section_id):
    """
    get the list of enrollments for the canvas section
    """
    enrollment_list = get_all_list_data(SDK_CONTEXT,
                                        enrollments.list_enrollments_sections,
                                        canvas_section_id)
    sis_user_id_list = []
    for enrollment in enrollment_list:
        sis_user_id = enrollment['user'].get('sis_user_id')
        if sis_user_id:
            sis_user_id_list.append(sis_user_id)
    return sis_user_id_list
Ejemplo n.º 28
0
def get_sections_list(request_context, course_id):
    """
    Returns a list of sections for the course.
    https://canvas.instructure.com/doc/api/sections.html#method.sections_api.index
    """
    results = get_all_list_data(request_context, sections.list_course_sections,
                                course_id, "students")
    try:
        returned_sections = filter(lambda x: x['students'] is not None,
                                   results)
    except KeyError:
        return []
    return list(returned_sections)
Ejemplo n.º 29
0
def get_external_tool_id(api_auth, canvas_course_id):
    context = _get_context(api_auth)
    tools = get_all_list_data(context, external_tools.list_external_tools_courses, canvas_course_id)
    domain = settings.EXTERNAL_TOOL_DOMAIN
    tool_id = next((x['id'] for x in tools if x.get('domain', None) == domain), None)
    if not tool_id:
        tool = external_tools.create_external_tool_courses(
            context, canvas_course_id, 'Open edX at Harvard', 'anonymous',
            settings.EDX_LTI_KEY, settings.EDX_LTI_SECRET, domain=domain
        )
        tool_id = tool.json().get('id', None)

    return tool_id
def get_account_list_from_canvas():
    """
    Get the list of all sub-accounts of the Harvard root account 
    and build a list of the account id's.  
    """
    sub_account_list = get_all_list_data(SDK_CONTEXT, accounts.get_sub_accounts_of_account,
                                         settings.MANAGE_SECTIONS.get('ROOT_ACCOUNT', 1), recursive=True)
    sub_list = []
    for a in sub_account_list:
        sub_account_id = a.get('id')
        if sub_account_id:
            sub_list.append(sub_account_id)
    return sorted(sub_list)
Ejemplo n.º 31
0
def fetch_allevents(id):
    '''Fetches assignments and events for course with given id'''
    if oauthtoken is None:
        raise_exception()

    # Create request context
    req_context = request_context.RequestContext(oauthtoken, baseurl)

    # Create separate parameters for assignment event and calendar event requests
    assignparams = {
        "all_events": "true",
        "type": "assignment",
        "context_codes[]": "course_" + str(id)
    }
    eventparams = {
        "all_events": "true",
        "context_codes[]": "course_" + str(id)
    }

    # Make requests, making sure to get all the data
    assignments = get_all_list_data(req_context,
                                    base.get,
                                    baseurl + "/v1/calendar_events",
                                    params=assignparams,
                                    auth_token=oauthtoken)
    events = get_all_list_data(req_context,
                               base.get,
                               baseurl + "/v1/calendar_events",
                               params=eventparams,
                               auth_token=oauthtoken)

    # Merge lists
    allevents = assignments + events

    # Sort and filter, separating into a tuple
    filtered = filter_undated(sort_events(allevents))

    return filtered
def fetch_allevents(id):
	'''Fetches assignments and events for course with given id'''
	if oauthtoken is None:
		raise_exception()
		
	# Create request context
	req_context = request_context.RequestContext(oauthtoken, baseurl)

	# Create separate parameters for assignment event and calendar event requests
	assignparams = {"all_events": "true", "type" : "assignment", "context_codes[]" : "course_" + str(id)}
	eventparams = {"all_events": "true", "context_codes[]" : "course_" + str(id)} 

	# Make requests, making sure to get all the data
	assignments = get_all_list_data(req_context, base.get, baseurl + "/v1/calendar_events", params=assignparams, auth_token=oauthtoken)
	events = get_all_list_data(req_context, base.get, baseurl + "/v1/calendar_events", params=eventparams, auth_token=oauthtoken)

	# Merge lists
	allevents = assignments + events

	# Sort and filter, separating into a tuple
	filtered = filter_undated(sort_events(allevents))

	return filtered
Ejemplo n.º 33
0
    def test_get_all_list_data_returns_initial_response_list_json_when_response_has_no_paged_results(self, mock_next):
        """
        Assert that result of call to get_all_list_data for a request that's a list of data and has no paged results returns
        the json list.
        """
        expected_json = [{'first': 'json'}]
        mock_next.return_value = iter([])
        mock_function = mock.Mock(name='mock-function')
        mock_response = self.build_response_mock(json_data=expected_json)
        mock_function.return_value = mock_response

        results = utils.get_all_list_data(self.req_ctx, mock_function)
        self.assertEqual(
            results, expected_json, "The json data returned by get_all function should match up with expected_json list")
Ejemplo n.º 34
0
def get_courses_for_account_in_term(account_id, enrollment_term_id,
                                    include_sections=False):
    kwargs = {
        'account_id': account_id,
        'enrollment_term_id': enrollment_term_id,
    }
    if include_sections:
        kwargs['include'] = 'sections'

    try:
        result = get_all_list_data(SDK_CONTEXT, accounts.list_active_courses_in_account, **kwargs)
    except CanvasAPIError:
        logger.error('Unable to get courses for account {}, term {}'.format(account_id, enrollment_term_id))
        raise
    return result
Ejemplo n.º 35
0
def get_courses_for_account_in_term(account_id, enrollment_term_id,
                                    include_sections=False):
    kwargs = {
        'account_id': account_id,
        'enrollment_term_id': enrollment_term_id,
    }
    if include_sections:
        kwargs['include'] = 'sections'

    try:
        result = get_all_list_data(SDK_CONTEXT, accounts.list_active_courses_in_account, **kwargs)
    except CanvasAPIError:
        logger.error('Unable to get courses for account {}, term {}'.format(account_id, enrollment_term_id))
        raise
    return result
def fetch_assigngroups(id):
	'''Fetches assignment groups for course with given id'''
	if oauthtoken is None:
		raise_exception()

	# Create request context
	req_context = request_context.RequestContext(oauthtoken, baseurl)

	# URL for request
	url = baseurl + "/v1/courses/" + str(id) + "/assignment_groups"

	# Make request, making sure to get all results
	groups = get_all_list_data(req_context, base.get, url, auth_token=oauthtoken)

	return groups
def get_account_list_from_canvas():
    """
    Get the list of all sub-accounts of the Harvard root account 
    and build a list of the account id's.  
    """
    sub_account_list = get_all_list_data(SDK_CONTEXT,
                                         accounts.get_sub_accounts_of_account,
                                         settings.MANAGE_SECTIONS.get(
                                             'ROOT_ACCOUNT', 1),
                                         recursive=True)
    sub_list = []
    for a in sub_account_list:
        sub_account_id = a.get('id')
        if sub_account_id:
            sub_list.append(sub_account_id)
    return sorted(sub_list)
Ejemplo n.º 38
0
def get_submissions_with_rubric_assessments(request_context, course_id,
                                            assignment_ids):
    '''
    Returns the submission and rubric assessment data for each assignment.
    https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.index
    '''
    include = "rubric_assessment"
    results = []
    for assignment_id in assignment_ids:
        list_data = get_all_list_data(
            request_context, submissions.list_assignment_submissions_courses,
            course_id, assignment_id, include)
        results.append({
            "assignment_id": assignment_id,
            "submissions": list_data,
        })
    return results
Ejemplo n.º 39
0
def get_students_list(request_context, course_id):
    '''
    Returns a list of all students in the course.
    
    https://canvas.instructure.com/doc/api/courses.html#method.courses.users
    '''
    results = get_all_list_data(request_context,
                                courses.list_users_in_course_users,
                                course_id,
                                "email",
                                enrollment_type="student")
    students = sorted([{
        "sortable_name": x['sortable_name'],
        "id": x['id']
    } for x in results],
                      key=lambda x: x['sortable_name'])
    return list(students)
def get_canvas_sections_list(canvas_course_id):
    """
    Get a list of the sections exluding the primary section for the given canvas_course_id. 
    We don't want primary sections. Primary sections are ones where the
    there exists an sis_section_id that the same as the sis_course_id. We 
    also don't want sections with no name.  
    """
    canvas_course_sections = get_all_list_data(SDK_CONTEXT, sections.list_course_sections, canvas_course_id)
    canvas_course_sections_list = []
    for canvas_section in canvas_course_sections:
        canvas_section_id = canvas_section.get('id')
        canvas_section_name = canvas_section.get('name')
        sis_course_id = canvas_section.get('sis_course_id')
        sis_section_id = canvas_section.get('sis_section_id')
        if canvas_section_id and (sis_course_id != sis_section_id) and canvas_section_name:
            canvas_course_sections_list.append(canvas_section_id)
    return canvas_course_sections_list
Ejemplo n.º 41
0
def fetch_assigngroups(id):
    '''Fetches assignment groups for course with given id'''
    if oauthtoken is None:
        raise_exception()

    # Create request context
    req_context = request_context.RequestContext(oauthtoken, baseurl)

    # URL for request
    url = baseurl + "/v1/courses/" + str(id) + "/assignment_groups"

    # Make request, making sure to get all results
    groups = get_all_list_data(req_context,
                               base.get,
                               url,
                               auth_token=oauthtoken)

    return groups
Ejemplo n.º 42
0
    def test_get_all_list_data_returns_concatenated_list_of_json_results(self, mock_next):
        """
        Assert that result of call to get_all_list_data is a single concatenated list of json data from
        series of "next" responses.
        """
        expected_json = [
            {'first': 'json'}, {'second': 'json'}, {'third': 'json'}, {'fourth': 'json'}]
        # Simulate an initial response with 3 additional pages
        mock_next.return_value = iter([
            self.build_response_mock(json_data=[expected_json[1]]),
            self.build_response_mock(json_data=[expected_json[2]]),
            self.build_response_mock(json_data=[expected_json[3]]),
        ])
        mock_function = mock.Mock(name='mock-function')
        mock_response = self.build_response_mock(json_data=[expected_json[0]])
        mock_function.return_value = mock_response

        results = utils.get_all_list_data(self.req_ctx, mock_function)
        self.assertEqual(
            results, expected_json, "The json list of data returned by get_all function should be the fully concatenated list of json")
def get_enrolled_roles_for_user_ids(canvas_course_id, search_results_user_ids):
    """
    Look for any ids returned from the search query that match ids already
    enrolled in the course.  If we find a match, add them to the found_ids.
    This list will be used in the template to disable the checkbox for ids that
    are already enrolled in the course.  Do not match XIDs.
    """
    canvas_enrollments = get_all_list_data(
            SDK_CONTEXT, enrollments.list_enrollments_courses, canvas_course_id)

    found_ids = defaultdict(list)
    for enrollment in canvas_enrollments:
        try:
            sis_user_id = enrollment['user']['sis_user_id']
        except KeyError:
            continue
        else:
            if sis_user_id in search_results_user_ids:
                found_ids[sis_user_id].append(enrollment['role'])
    return found_ids
Ejemplo n.º 44
0
def get_external_tool_id(api_auth, canvas_course_id):
    context = _get_context(api_auth)
    tools = get_all_list_data(context,
                              external_tools.list_external_tools_courses,
                              canvas_course_id)
    domain = settings.EXTERNAL_TOOL_DOMAIN
    tool_id = next((x['id'] for x in tools if x.get('domain', None) == domain),
                   None)
    if not tool_id:
        tool = external_tools.create_external_tool_courses(
            context,
            canvas_course_id,
            'Open edX at Harvard',
            'anonymous',
            settings.EDX_LTI_KEY,
            settings.EDX_LTI_SECRET,
            domain=domain)
        tool_id = tool.json().get('id', None)

    return tool_id
def get_canvas_sections_list(canvas_course_id):
    """
    Get a list of the sections exluding the primary section for the given canvas_course_id. 
    We don't want primary sections. Primary sections are ones where the
    there exists an sis_section_id that the same as the sis_course_id. We 
    also don't want sections with no name.  
    """
    canvas_course_sections = get_all_list_data(SDK_CONTEXT,
                                               sections.list_course_sections,
                                               canvas_course_id)
    canvas_course_sections_list = []
    for canvas_section in canvas_course_sections:
        canvas_section_id = canvas_section.get('id')
        canvas_section_name = canvas_section.get('name')
        sis_course_id = canvas_section.get('sis_course_id')
        sis_section_id = canvas_section.get('sis_section_id')
        if canvas_section_id and (sis_course_id !=
                                  sis_section_id) and canvas_section_name:
            canvas_course_sections_list.append(canvas_section_id)
    return canvas_course_sections_list
Ejemplo n.º 46
0
# SDK script to get the numbers of page views and participations in a Canvas course from analytics using the SDK
import csv
from canvas_sdk import RequestContext
from pprint import pprint
from canvas_sdk.methods import analytics
from canvas_sdk.utils import get_all_list_data
from secure import oauth_token

data=[]

canvas_url = 'https://canvas.harvard.edu/api/'  # for production

SDK_CONTEXT = RequestContext(oauth_token, canvas_url)
# use the SDK to make the request to the Canvas API to the canvas instance defined in canvas_url

response = get_all_list_data(SDK_CONTEXT, analytics.get_course_level_student_summary_data, course_id=495)
# save the response from the SDK call for a particular course_id
# use the API to get move through all pages

length = len(response)

# save the id, participation, and page_view data from the response
for c in range(0,length):
	print c
	user_id = response[c]['id']
	participations = response[c]['participations']
	page_views = response[c]['page_views']
	data.append([user_id, participations, page_views])

# write the data saved from the response to a CSV
with open('analytics.csv', 'wb') as f:
Ejemplo n.º 47
0
def main(request):



    #get the course ID of current course
    canvas_course_id = request.session['LTI_LAUNCH'].get('custom_canvas_course_id')
    logger.debug('////////////////////////////////////>')
    logger.debug('canvas_course_id=%s' % canvas_course_id)
    logger.debug('////////////////////////////////////>')
    

    #call to get course name for roster header
    canvas_course_name = get_all_list_data(SDK_CONTEXT, courses.get_single_course_courses, canvas_course_id, "all_courses")
    logger.debug('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>')
    logger.debug(canvas_course_name)
    logger.debug('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>')

    #get a list of STUDENTS in the current course, we will use only the user_id from the list
    #the 'avatar_url' is just a required option, and we will actually use the avatar_url from the profile list below
    enrollmentGet = {}
    try:
        enrollmentGet = get_all_list_data(SDK_CONTEXT, courses.list_users_in_course_users, canvas_course_id, 'avatar_url', enrollment_type='student')
    except CanvasAPIError as api_error:
        logger.debug((canvas_course_id, api_error))
    
    #get a list of TEACHERS in the current course.  Should be automatically hidden with js in lti_view.thml, and can be toggled with a switch
    faculty = {}
    try:
        faculty = get_all_list_data(SDK_CONTEXT, courses.list_users_in_course_users, canvas_course_id, 'avatar_url', enrollment_type='teacher')
    except CanvasAPIError as api_error:
        logger.debug((canvas_course_id, api_error))
    
    #for each student user in the course, get their user_id
    userID = []
    for d in enrollmentGet:
        userIdSingle = d['id']
        userID.append(userIdSingle)
    logger.debug('*********************************************>')
    logger.debug('userID=%s' %userID)
    logger.debug('*********************************************>')

    facultyID = []
    for d in faculty:
        facultyIdSingle = d['id']
        facultyID.append(facultyIdSingle)
    logger.debug('++++++++++++++++++++++++++++++++++++++++++++++++>')
    logger.debug('facultyID=%s' %facultyID)
    logger.debug('++++++++++++++++++++++++++++++++++++++++++++++++>')


    #Run the user profile call for each student user_id we just got, 
    #and use what we need in the html
    userGet = []
    for l in userID:  
        try:
            studentFull = get_all_list_data(SDK_CONTEXT, users.get_user_profile, l)
            userGet.append(studentFull)
        except CanvasAPIError as api_error:
            logger.debug('CanvasAPIError in get_all_list_data enrollments.list_enrollments_courses call for canvas_course_id=%s. Exception=%s:' % (canvas_course_id, api_error))
   
    facultyGet = []
    for l in facultyID:  
        try:
            facultyFull = get_all_list_data(SDK_CONTEXT, users.get_user_profile, l)
            facultyGet.append(facultyFull)         
        except CanvasAPIError as api_error:
            logger.debug('CanvasAPIError in get_all_list_data enrollments.list_enrollments_courses call for canvas_course_id=%s. Exception=%s:' % (canvas_course_id, api_error))



    #dictionary definitions for the lti_view html
    return render(request, 'canvasPR_app/lti_view.html', {'request': request, 'pages': enrollmentGet, 'userGet': userGet, 'facultyGet': facultyGet, 'courseName': canvas_course_name})
Ejemplo n.º 48
0
def get_courses(api_auth):
    context = _get_context(api_auth)
    get_all_list_data(context, courses.list_your_courses, 'term')
Ejemplo n.º 49
0
def get_module_list(api_token, canvas_course_id):
    context = _get_context(api_token)
    return get_all_list_data(context, modules.list_modules, canvas_course_id, 'items')
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 get_enrollments_added_through_tool(sis_course_id):
    """
    This method fetches the primary section enrollments for this course and
    then filters out the course enrollees that are fed via sis import feed
    process or cross-registration.
    """
    logger.debug(u'get_enrollments_added_through_tool(course_instance_id=%s)',
                 sis_course_id)

    section_id_param = 'sis_section_id:' + str(sis_course_id)
    try:
        canvas_enrollments = get_all_list_data(
                SDK_CONTEXT, enrollments.list_enrollments_sections,
                section_id_param)
    except CanvasAPIError as api_error:
        logger.error(
            u'CanvasAPIError in get_all_list_data call for sis_course_id=%s. '
            u'Exception=%s:', sis_course_id, api_error)
        return []
    logger.debug(u"size of enrollees in canvas= %s" % len(canvas_enrollments))

    # get the list of enrolles from Course Manager DB, who are eligible to be
    # deleted via this tool.  This is achieved by using a filter to exclude
    # users with values equal to e.g. 'xmlfeed','fasfeed', or 'xreg_map' in the
    # 'SOURCE' column, which indicates that these users were fed from the
    # registrar feed or xreg.  Note: The code is excluding any source containing
    # 'feed' to capture various feed sources like 'xmlfeed','fasfeed','icfeed'
    # etc.

    eligible_ids = set()
    query = (Q(course_instance_id=sis_course_id) &
             (Q(source__isnull=True) |
              ~(Q(source__icontains='feed') | Q(source='xreg_map'))))
    for model in COURSE_MEMBER_CLASSES:
        try:
            ids = list(model.objects.filter(query).values_list('user_id',
                                                               'role_id'))
        except Exception as e:
            logger.exception(u'unable to look up course members in %s: %s',
                             model._meta.db_table, e)
        else:
            logger.debug(u'eligible %s members = %s',
                         model._meta.db_table, ids)
        eligible_ids.update(ids)
    logger.debug(u'full set of eligible user/role ids: %s', eligible_ids)

    # get a mapping of canvas role_id to UserRole ids
    canvas_role_to_user_role = get_canvas_to_user_role_id_map()

    # get the updated (or cached) Canvas role list so we can show the right
    # Canvas role labels for the enrollments
    canvas_roles_by_role_id = get_roles_for_account_id('self')

    # Further filter users to remove users who may not yet be be in canvas.
    # For the moment we are treating COURSEMANAGER as the single source of truth
    # for who should be enrolled in a course, but we also need to get Canvas
    # enrollee attributes like enrollee_id, which is required for deleting the
    # user further on. Hence we disallow deletion of anyone who's not also
    # accurately represented in Canvas.

    filtered_enrollments = []
    for enrollment in canvas_enrollments:
        if enrollment.get('user'):
            # If sis_user_id exists, use it; if not, use login_id; if neither
            # exist then log it and do not include
            user_id = (enrollment['user'].get('sis_user_id') or
                           enrollment['user'].get('login_id'))
            user_role_id = canvas_role_to_user_role[enrollment['role_id']]
            if user_id and (user_id, user_role_id) in eligible_ids:
                enrollment.update({
                    'user_role_id': user_role_id,
                    'canvas_role_label': canvas_roles_by_role_id.get(
                        enrollment['role_id'])['label']})
                filtered_enrollments.append(enrollment)
                logger.debug(u'MP filter out registrar fed: Allowing (%s, %s)',
                             user_id, user_role_id)
            else:
                # Log the users not yet in Canvas or who do not match because
                # they're missing an sis_user_id or login_id.  These users will
                # not be available for removal in the tool. Assumes all users
                # have sortable_name and assumes sis_user_id is the source of
                # truth in Canvas (see comment above re:TLT-705)
                logger.info(
                    u'Manage People: Canvas %s (Canvas role_id %s, '
                    u'user_role_id %s) enrollment for user %s (CM user id %s) '
                    u'was either not found in the Coursemanager DB, or was '
                    u'registrar-fed.  Not including it in the results list.',
                    enrollment['role'],
                    enrollment['role_id'],
                    canvas_role_to_user_role[enrollment['role_id']],
                    enrollment['user'].get('sortable_name'),
                    enrollment['user'].get('sis_user_id'))
        else:
            # Problem with canvas enrollee data structure
            logger.info(
                u'Manage People: Canvas enrollment does not have user '
                u'information associated with it. Enrollment info: %s',
                enrollment)

    # Sort the users by sortable_name
    filtered_enrollments.sort(key=lambda x: x['user']['sortable_name'])
    logger.debug(u'size of filtered and sorted enrollments= %s',
                 len(filtered_enrollments))

    # add custom display badge information for enrollees to the filtered
    # Canvas enrollment objects badge information is used on user_form to
    # identify different university ID types and distinguish  multiple IDs
    # for the same user (i.e. enrollments where the user name is identical)
    user_id_list = [enrollment['user'].get('sis_user_id')
                        for enrollment in filtered_enrollments]
    user_badge_info_mapping = get_badge_info_for_users(user_id_list)
    for enrollment in filtered_enrollments:
        user_id = enrollment['user'].get('sis_user_id')
        if user_id and user_id in user_badge_info_mapping:
            enrollment['badge_label_name'] = user_badge_info_mapping[user_id]
        # Check if the given enrollment can be deleted in the current tool
        # If it can not, we want to disable the delete option in the template
        user_role = get_user_role_if_permitted(sis_course_id, enrollment['user_role_id'])
        enrollment['can_be_deleted'] = True if user_role is not None else False

    return filtered_enrollments