示例#1
0
def get_user_program_info(user, edx_client):
    """
    Provides a detailed serialization all of a User's enrolled Programs with enrollment/grade info

    Args:
        user (User): A User
        edx_client (EdxApi): An EdxApi instance

    Returns:
        list: Enrolled Program information
    """
    # update cache
    # NOTE: this part can be moved to an asynchronous task
    if edx_client is not None:
        try:
            for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
                CachedEdxDataApi.update_cache_if_expired(
                    user, edx_client, cache_type)
        except InvalidCredentialStored:
            # this needs to raise in order to force the user re-login
            raise
        except:  # pylint: disable=bare-except
            log.exception('Impossible to refresh edX cache')

    response_data = {
        "programs": [],
        "is_edx_data_fresh": CachedEdxDataApi.are_all_caches_fresh(user)
    }
    all_programs = (Program.objects.filter(
        live=True, programenrollment__user=user).prefetch_related(
            'course_set__courserun_set'))
    for program in all_programs:
        mmtrack_info = get_mmtrack(user, program)
        response_data['programs'].append(get_info_for_program(mmtrack_info))
    return response_data
示例#2
0
def get_user_program_info(user, edx_client):
    """
    Provides a detailed serialization all of a User's enrolled Programs with enrollment/grade info

    Args:
        user (User): A User
        edx_client (EdxApi): An EdxApi instance

    Returns:
        list: Enrolled Program information
    """
    # update cache
    # NOTE: this part can be moved to an asynchronous task
    if edx_client is not None:
        try:
            for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
                CachedEdxDataApi.update_cache_if_expired(user, edx_client, cache_type)
        except InvalidCredentialStored:
            # this needs to raise in order to force the user re-login
            raise
        except:  # pylint: disable=bare-except
            log.exception('Impossible to refresh edX cache')

    response_data = {
        "programs": [],
        "is_edx_data_fresh": CachedEdxDataApi.are_all_caches_fresh(user)
    }
    all_programs = (
        Program.objects.filter(live=True, programenrollment__user=user).prefetch_related('course_set__courserun_set')
    )
    for program in all_programs:
        mmtrack_info = get_mmtrack(user, program)
        response_data['programs'].append(get_info_for_program(mmtrack_info))
    return response_data
示例#3
0
def refresh_user_data(user_id):
    """
    Refresh the edx cache data for a user.

    Note that this function will not raise an exception on error, instead the errors are logged.

    Args:
        user_id (int): The user id
    """
    # pylint: disable=bare-except
    try:
        user = User.objects.get(pk=user_id)
    except:
        log.exception('edX data refresh task: unable to get user "%s"',
                      user_id)
        return

    # get the credentials for the current user for edX
    try:
        user_social = get_social_auth(user)
    except:
        log.exception('user "%s" does not have edX credentials', user.username)
        return

    try:
        utils.refresh_user_token(user_social)
    except:
        save_cache_update_failure(user_id)
        log.exception("Unable to refresh token for student %s", user.username)
        return

    try:
        edx_client = EdxApi(user_social.extra_data, settings.EDXORG_BASE_URL)
    except:
        log.exception("Unable to create an edX client object for student %s",
                      user.username)
        return

    for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
        try:
            CachedEdxDataApi.update_cache_if_expired(user, edx_client,
                                                     cache_type)
        except:
            save_cache_update_failure(user_id)
            log.exception("Unable to refresh cache %s for student %s",
                          cache_type, user.username)
            continue
示例#4
0
 def test_update_cache_if_expired_http_errors(self, status_code, mock_enr):
     """
     Test for update_cache_if_expired in case a backend function raises an HTTPError
     """
     def raise_http_error(*args, **kwargs):  # pylint: disable=unused-argument
         """Mock function to raise an exception"""
         error = HTTPError()
         error.response = MagicMock()
         error.response.status_code = status_code
         raise error
     mock_enr.side_effect = raise_http_error
     if status_code in (400, 401):
         with self.assertRaises(InvalidCredentialStored):
             CachedEdxDataApi.update_cache_if_expired(self.user, self.edx_client, CachedEdxDataApi.ENROLLMENT)
     else:
         with self.assertRaises(HTTPError):
             CachedEdxDataApi.update_cache_if_expired(self.user, self.edx_client, CachedEdxDataApi.ENROLLMENT)
    def test_update_cache_if_expired(self, mock_enr, mock_cert, mock_grade):
        """Test for update_cache_if_expired"""
        all_mocks = (
            mock_enr,
            mock_cert,
            mock_grade,
        )

        with self.assertRaises(ValueError):
            CachedEdxDataApi.update_cache_if_expired(self.user,
                                                     self.edx_client,
                                                     'footype')

        # if there is no entry in the UserCacheRefreshTime the cache is not fresh and needs to be refreshed
        for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
            # the following is possible only because a mocked function is called
            assert UserCacheRefreshTime.objects.filter(
                user=self.user).exists() is False
            CachedEdxDataApi.update_cache_if_expired(self.user,
                                                     self.edx_client,
                                                     cache_type)
        for mock_func in all_mocks:
            assert mock_func.called is True
            mock_func.reset_mock()

        # if we create a fresh entry in the UserCacheRefreshTime, no update is called
        now = now_in_utc()
        user_cache = UserCacheRefreshTimeFactory.create(
            user=self.user,
            enrollment=now,
            certificate=now,
            current_grade=now,
        )
        for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
            CachedEdxDataApi.update_cache_if_expired(self.user,
                                                     self.edx_client,
                                                     cache_type)
        for mock_func in all_mocks:
            assert mock_func.called is False
            mock_func.reset_mock()

        # moving back the last access time, the functions are called again
        yesterday = now - timedelta(days=1)
        user_cache.enrollment = yesterday
        user_cache.certificate = yesterday
        user_cache.current_grade = yesterday
        user_cache.save()
        for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
            CachedEdxDataApi.update_cache_if_expired(self.user,
                                                     self.edx_client,
                                                     cache_type)
        for mock_func in all_mocks:
            assert mock_func.called is True
示例#6
0
def refresh_user_data(user_id):
    """
    Refresh the edx cache data for a user.

    Note that this function will not raise an exception on error, instead the errors are logged.

    Args:
        user_id (int): The user id
    """
    # pylint: disable=bare-except
    try:
        user = User.objects.get(pk=user_id)
    except:
        log.exception('edX data refresh task: unable to get user "%s"', user_id)
        return

    # get the credentials for the current user for edX
    try:
        user_social = get_social_auth(user)
    except:
        log.exception('user "%s" does not have edX credentials', user.username)
        return

    try:
        utils.refresh_user_token(user_social)
    except:
        save_cache_update_failure(user_id)
        log.exception("Unable to refresh token for student %s", user.username)
        return

    try:
        edx_client = EdxApi(user_social.extra_data, settings.EDXORG_BASE_URL)
    except:
        log.exception("Unable to create an edX client object for student %s", user.username)
        return

    for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
        try:
            CachedEdxDataApi.update_cache_if_expired(user, edx_client, cache_type)
        except:
            save_cache_update_failure(user_id)
            log.exception("Unable to refresh cache %s for student %s", cache_type, user.username)
            continue
    def test_update_cache_if_expired_http_errors(self, status_code, mock_enr):
        """
        Test for update_cache_if_expired in case a backend function raises an HTTPError
        """
        def raise_http_error(*args, **kwargs):  # pylint: disable=unused-argument
            """Mock function to raise an exception"""
            error = HTTPError()
            error.response = MagicMock()
            error.response.status_code = status_code
            raise error

        mock_enr.side_effect = raise_http_error
        if status_code in (400, 401):
            with self.assertRaises(InvalidCredentialStored):
                CachedEdxDataApi.update_cache_if_expired(
                    self.user, self.edx_client, CachedEdxDataApi.ENROLLMENT)
        else:
            with self.assertRaises(HTTPError):
                CachedEdxDataApi.update_cache_if_expired(
                    self.user, self.edx_client, CachedEdxDataApi.ENROLLMENT)
示例#8
0
    def test_update_cache_if_expired(self, mock_enr, mock_cert, mock_grade):
        """Test for update_cache_if_expired"""
        all_mocks = (mock_enr, mock_cert, mock_grade, )

        with self.assertRaises(ValueError):
            CachedEdxDataApi.update_cache_if_expired(self.user, self.edx_client, 'footype')

        # if there is no entry in the UserCacheRefreshTime the cache is not fresh and needs to be refreshed
        for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
            # the following is possible only because a mocked function is called
            assert UserCacheRefreshTime.objects.filter(user=self.user).exists() is False
            CachedEdxDataApi.update_cache_if_expired(self.user, self.edx_client, cache_type)
        for mock_func in all_mocks:
            assert mock_func.called is True
            mock_func.reset_mock()

        # if we create a fresh entry in the UserCacheRefreshTime, no update is called
        now = now_in_utc()
        user_cache = UserCacheRefreshTimeFactory.create(
            user=self.user,
            enrollment=now,
            certificate=now,
            current_grade=now,
        )
        for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
            CachedEdxDataApi.update_cache_if_expired(self.user, self.edx_client, cache_type)
        for mock_func in all_mocks:
            assert mock_func.called is False
            mock_func.reset_mock()

        # moving back the last access time, the functions are called again
        yesterday = now - timedelta(days=1)
        user_cache.enrollment = yesterday
        user_cache.certificate = yesterday
        user_cache.current_grade = yesterday
        user_cache.save()
        for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
            CachedEdxDataApi.update_cache_if_expired(self.user, self.edx_client, cache_type)
        for mock_func in all_mocks:
            assert mock_func.called is True