Esempio n. 1
0
    def get_oauth_access_token(self):
        """
        Request OpenEdx API OAuth2 token.

        Token type: JWT (reference: https://jwt.io/).
        :return: access_token, expires_at
        """
        url = "{host_url}{token_url}".format(
            host_url=self.content_source.host_url, token_url=self.TOKEN_URL)
        log.debug("Requesting oauth token: (url={})".format(url))
        try:
            oauth_client = self.content_source.o_auth_client
            access_token, expires_at = super().get_oauth_access_token(
                url=url,
                client_id=oauth_client.client_id,
                client_secret=oauth_client.client_secret,
                token_type='jwt',
            )
        except ObjectDoesNotExist:
            raise HttpClientError(
                "OAuth token request failure. Please, configure OAuth client in order to be able make API requests."
            )
        except ValueError:
            log.exception(
                "You may want to check your OAuth registration on LTI Provider."
                "LTI Provider may be disabled (to enable: LMS config > FEATURES > ENABLE_OAUTH2_PROVIDER: true"
            )
            raise HttpClientError("OAuth token request failure.")
        except RequestException:
            log.exception(
                'OAuth2 token request to the OpenEdx LTI Provider failed.')
            raise HttpClientError("OAuth token request failure.")
        return access_token, expires_at
def get_available_blocks(source_id, course_id=''):
    """
    Content Source API requester.

    Fetches all source blocks from the course with the given ID.
    Blocks data is filtered by `apply_data_filter`.
    :param course_id: Course id
    :param source_id: LtiConsumer id
    :return: (list) blocks data
    """
    content_source = get_active_content_sources(source_id).first()
    all_blocks = []

    # Get API client instance:
    api = api_client_factory(content_source=content_source)
    try:
        # filter function will be applied to api response
        all_blocks.extend(
            apply_data_filter(api.get_course_blocks(course_id),
                              filters=[
                                  'id', 'block_id', 'display_name', 'lti_url',
                                  'type', 'content_source_id'
                              ],
                              context_id=course_id,
                              content_source_id=content_source.id))
    except HttpNotFoundError:
        raise HttpClientError(
            _("Requested course not found. Check `course_id` url encoding."))
    except HttpClientError as exc:
        raise HttpClientError(_("Not valid query: {}").format(exc.message))

    return all_blocks
Esempio n. 3
0
    def test_bad_solitude_request(self):
        self.setup_generic_buyer()
        exc = HttpClientError('bad request')
        exc.content = {'nonce': ['This field is required.']}
        self.solitude.braintree.paymethod.post.side_effect = exc

        res, data = self.post()
        self.assert_form_error(res, ['nonce'])
Esempio n. 4
0
    def test_bad_solitude_request(self):
        exc = HttpClientError('bad request')
        exc.content = {'product_id': ['Invalid product.']}
        self.solitude.braintree.sale.post.side_effect = exc

        res, data = self.post()
        self.assert_error_response(
            res, msg_patterns={'product_id': exc.content['product_id'][0]})
Esempio n. 5
0
 def test_fatal_code(self):
     response_with_200 = HttpResponse(status=200)
     response_with_400 = HttpResponse(status=400)
     response_with_429 = HttpResponse(status=429)
     response_with_504 = HttpResponse(status=504)
     self.assertFalse(_fatal_code(HttpClientError(response=response_with_200)))  # pylint: disable=protected-access
     self.assertTrue(_fatal_code(HttpClientError(response=response_with_400)))  # pylint: disable=protected-access
     self.assertFalse(_fatal_code(HttpClientError(response=response_with_429)))  # pylint: disable=protected-access
     self.assertFalse(_fatal_code(HttpClientError(response=response_with_504)))  # pylint: disable=protected-access
Esempio n. 6
0
 def test_fatal_code(self):
     response_with_200 = HttpResponse(status=200)
     response_with_429 = HttpResponse(status=429)
     self.assertEqual(self.loader_class._fatal_code(  # pylint: disable=protected-access
         HttpClientError(response=response_with_200)), True
     )
     self.assertEqual(self.loader_class._fatal_code(  # pylint: disable=protected-access
         HttpClientError(response=response_with_429)), False
     )
Esempio n. 7
0
 def test_fatal_code(self):
     response_with_200 = HttpResponse(status=200)
     response_with_400 = HttpResponse(status=400)
     response_with_429 = HttpResponse(status=429)
     response_with_504 = HttpResponse(status=504)
     assert not _fatal_code(HttpClientError(response=response_with_200))
     assert _fatal_code(HttpClientError(response=response_with_400))
     assert not _fatal_code(HttpClientError(response=response_with_429))
     assert not _fatal_code(HttpClientError(response=response_with_504))
Esempio n. 8
0
    def test_bad_request_with_content(self):
        exc = HttpClientError('400')
        # Simulate a form error.
        exc.content = {'field-name': ['was invalid']}

        self.solitude.services.status.post.side_effect = exc
        res, data = self.post()
        eq_(data['error_message'], 'Bad Request')
        eq_(data['error_response'], exc.content)
        eq_(res.status_code, 400)
    def test_bad_solitude_request(self):
        self.setup_generic_buyer()
        self.setup_no_subscription_yet()
        exc = HttpClientError('bad request')
        exc.content = {'nonce': ['This field is required.']}
        self.solitude.braintree.paymethod.post.side_effect = exc

        res, data = self.post()
        self.assert_error_response(
            res, msg_patterns={'nonce': exc.content['nonce'][0]})
Esempio n. 10
0
    def test_new_tenant_recoverable_error(self, OA_mock):
        with setup_fb_client() as fb_client_mock:
            response = MagicMock()

            response.json.return_value = {
                'postal_code': {
                    'code': 'E1002',
                    'message': "Postal code can't start with 999"
                }
            }

            fb_client_mock.create.side_effect = HttpClientError(
                response=response)
            OA_mock.get_resource.side_effect = [{
                'companyName': 'fake_company',
                'techContact': {
                    'email': '*****@*****.**'
                }
            }, {
                'subscriptionId': 555
            }]

            res = self.client.post('/connector/v1/tenant',
                                   headers=self.headers,
                                   data=self.new_tenant)
            fb_client_mock.create.assert_called()

        assert res.json['status'] == 'activationRequired'
        assert res.status_code == 202
Esempio n. 11
0
    def test_update_transcription_service_credentials_exceptions(
            self, mock_client, mock_logger):
        """
        Tests that the update transcription service credentials logs the exception occurring
        during communication with edx-video-pipeline.
        """
        error_content = '{"error_type": "1"}'
        mock_client.return_value.request = Mock(side_effect=HttpClientError(
            content=error_content))

        # try updating the transcription service credentials
        credentials_payload = {
            'org': 'mit',
            'provider': 'ABC Provider',
            'api_key': '61c56a8d0'
        }
        error_response, is_updated = update_3rd_party_transcription_service_credentials(
            **credentials_payload)

        # Assert the results.
        self.assertFalse(is_updated)
        self.assertDictEqual(error_response, json.loads(error_content))
        mock_logger.exception.assert_called_with(
            'Unable to update transcript credentials -- org={}, provider={}, response={}'
            .format(credentials_payload['org'],
                    credentials_payload['provider'], error_content))
Esempio n. 12
0
    def test_new_tenant_recoverable_error_invalid_zip(self, OA_mock):
        with setup_fb_client() as fb_client_mock:
            response = MagicMock()

            response.json.return_value = {
                'postal_code': {
                    'code': 'E1001',
                    'message': "Postal code must be a 5-digit number"
                }
            }

            fb_client_mock.create.side_effect = HttpClientError(
                response=response)
            OA_mock.get_resource.side_effect = [{
                'companyName': 'fake_company',
                'techContact': {
                    'email': '*****@*****.**'
                }
            }, {
                'subscriptionId': 555
            }]

            res = self.client.post('/connector/v1/tenant',
                                   headers=self.headers,
                                   data=self.new_tenant)
            fb_client_mock.create.assert_called()

        assert res.json['status'] == 'activationRequired'
        assert res.status_code == 202
        assert res.json['statusData']['perPropertyData'][0]['message']['text'] == \
            'The postal code must consist of five digits'
Esempio n. 13
0
    def test_new_tenant_unrecoverable_error(self, OA_mock):
        with setup_fb_client() as fb_client_mock:
            response = MagicMock()
            response.json.return_value = {
                'unknown_error': 'Something went wrong'
            }
            response.text = 'Something went wrong'
            response.status_code = 400
            fb_client_mock.create.side_effect = HttpClientError(
                response=response)
            OA_mock.get_resource.side_effect = [{
                'companyName': 'fake_company',
                'techContact': {
                    'email': '*****@*****.**'
                },
                'addressPostal': {
                    'postalCode': '11111'
                }
            }, {
                'subscriptionId': 555
            }]
            res = self.client.post('/connector/v1/tenant',
                                   headers=self.headers,
                                   data=self.new_tenant)
            fb_client_mock.create.assert_called()

        assert res.status_code == 500
Esempio n. 14
0
def get_available_courses(source_ids=None):
    """
    Fetch all available courses from all sources of from source with provided ID.

    :param source_ids: content provider's ID or list of the IDs
    :return: (list) course_ids
    """
    content_sources = get_active_content_sources(
        source_ids, not_allow_empty_source_id=False)

    all_courses = []

    for content_source in content_sources:
        # Get API client instance:
        api = api_client_factory(content_source=content_source)
        try:
            all_courses.extend(
                apply_data_filter(api.get_provider_courses(),
                                  filters=[
                                      'id', 'course_id', 'name', 'org',
                                      'content_source_id'
                                  ],
                                  content_source_id=content_source.id))
        except HttpClientError as exc:
            raise HttpClientError(_("Not valid query: {}").format(exc.message))

    return all_courses
Esempio n. 15
0
 def test_create_buyer_with_long_pin(self, slumber):
     slumber.generic.buyer.post.side_effect = HttpClientError(
         response=self.create_error_response(
             content={'pin': ['PIN_4_NUMBERS_LONG']}))
     buyer = client.create_buyer('with_long_pin', '12345')
     assert buyer.get('errors')
     eq_(buyer['errors'].get('pin'), [ERROR_STRINGS['PIN_4_NUMBERS_LONG']])
Esempio n. 16
0
 def test_create_buyer_with_existing_uuid(self, slumber):
     slumber.generic.buyer.post.side_effect = HttpClientError(
         response=self.create_error_response(
             content={'uuid': ['BUYER_UUID_ALREADY_EXISTS']}))
     buyer = client.create_buyer(self.uuid, '1234')
     assert buyer.get('errors')
     eq_(buyer['errors'].get('uuid'),
         [ERROR_STRINGS['BUYER_UUID_ALREADY_EXISTS']])
Esempio n. 17
0
 def test_create_buyer_with_short_pin(self, slumber):
     slumber.generic.buyer.post.side_effect = HttpClientError(
         response=self.create_error_response(content={
             'pin': [msg.PIN_4_NUMBERS_LONG]
         }))
     buyer = client.create_buyer('with_short_pin', self.email, pin='123')
     assert buyer.get('errors')
     eq_(buyer['errors'].get('pin'), [msg.PIN_4_NUMBERS_LONG])
Esempio n. 18
0
 def test_create_fail(self):
     err = {'broken': True}
     self.bango_patcher.package.post.side_effect = HttpClientError(
         content=err)
     res = self.client.post(self.payment_list,
                            data=json.dumps(payment_data))
     eq_(res.status_code, 500)
     eq_(json.loads(res.content), err)
Esempio n. 19
0
    def test_4xx_5xx(self):
        self.login()

        for status in [404, 403, 400, 500]:
            self.mocked_extract.get.side_effect = HttpClientError(
                response=mock.MagicMock(status_code=status))
            response = self.client.get(self.url)
            self.assertEqual(response.status_code, status)
Esempio n. 20
0
 def test_unset_needs_pin_reset_with_wrong_etag(self, slumber):
     wrong_etag = 'etag:wrong'
     buyer = mock.Mock(return_value=self.buyer_data)
     buyer.patch.side_effect = HttpClientError(
         response=self.create_error_response(
             status_code=412, content={'ERROR': ['RESOURCE_MODIFIED']}))
     slumber.generic.buyer.return_value = buyer
     with self.assertRaises(ResourceModified):
         client.set_needs_pin_reset(self.uuid, False, etag=wrong_etag)
Esempio n. 21
0
 def test_set_new_pin_for_reset_with_alpha_pin(self, slumber):
     buyer = mock.Mock(return_value=self.buyer_data)
     buyer.patch.side_effect = HttpClientError(
         response=self.create_error_response(
             content={'new_pin': ['PIN_ONLY_NUMBERS']}))
     slumber.generic.buyer.return_value = buyer
     res = client.set_new_pin(self.uuid, 'meow')
     assert res.get('errors')
     eq_(res['errors'].get('new_pin'), [ERROR_STRINGS['PIN_ONLY_NUMBERS']])
Esempio n. 22
0
 def _instance_get(self, **kwargs):
     try:
         return get_example_popit_json('{0}_{1}_embed={2}.json'.format(
             self.collection, self.object_id,
             kwargs.get('embed', 'membership')))
     except IOError as e:
         if e.errno == errno.ENOENT:
             raise HttpClientError('Client Error 404',
                                   content='Fake content not found')
         else:
             raise
    def test_failure(self):
        connection = mock.MagicMock()
        connection.oauth2.access_token.post.side_effect = HttpClientError(
            content='{"error": "invalid grant"}')
        self.mocked_get_auth_connection.return_value = connection

        response = self.client.post(self.url,
                                    data=self.credentials,
                                    follow=True)

        self.assertFalse(response.context_data["form"].is_valid())
        self.assertEqual(self.client.session.items(), [])
Esempio n. 24
0
 def test_proxy_error_responses(self):
     # Create a scenario where the proxied API raises an HTTP error.
     data = {'error': {'message': 'something not found'}}
     proxy_res = HttpResponse(data,
                              content_type='application/json',
                              status=404)
     proxy_res.json = data
     proxy_res.request = RequestFactory().get('http://api/some/endpoint')
     exc = HttpClientError(proxy_res.content, response=proxy_res)
     self.api.products.get.side_effect = exc
     res = self.request('get', '/reference/products?foo=bar', 'products')
     eq_(res.status_code, 404)
     eq_(res.json, {'error_message': 'something not found'})
Esempio n. 25
0
def get_active_content_sources(source_id=None, not_allow_empty_source_id=True):
    """
    Check that passed source_id parameter is valid.

    If there's only one active source provider - source_id parameter is not required, it will get first active.
    :param source_id: LtiConsumer object id
    :param not_allow_empty_source_id: if True - it will not allow empty source_id, if False - source_id could be None
    :return: queryset of content_sources
    :raise HttpClientError: if provided parameters are not valid
    """
    if not_allow_empty_source_id and not source_id:
        # if source_id is not provided and more than one active content_provider
        raise HttpClientError(
            _("Parameter source_id is mandatory if there's more than one active content source."
              ))

    content_sources = get_content_providers(source_id=source_id)

    if not content_sources:
        # if no active content sources
        raise HttpClientError(_("No active Content Provider"))

    return content_sources
Esempio n. 26
0
 def test_get_catalog_results_with_exception(self):
     """
     Verify `get_catalog_results` of CourseCatalogApiClient works as expected in case of exception.
     """
     responses.add(
         responses.POST,
         url=urljoin(self.api.catalog_url, self.api.SEARCH_ALL_ENDPOINT),
         body=HttpClientError(content='boom'),
     )
     logger = logging.getLogger('enterprise.api_client.discovery')
     handler = MockLoggingHandler(level="ERROR")
     logger.addHandler(handler)
     assert self.api.get_catalog_results(content_filter_query='query',
                                         query_params={'page': 2}) == {
                                             'next': None,
                                             'previous': None,
                                             'results': [],
                                         }
     expected_message = 'Failed to retrieve data from the catalog API. content -- [boom]'
     assert handler.messages['error'][0] == expected_message
Esempio n. 27
0
 def test_get_catalog_results_with_exception(self):
     """
     Verify `get_catalog_results` of CourseCatalogApiClient works as expected in case of exception.
     """
     responses.add(
         responses.POST,
         url=urljoin(self.api.catalog_url, self.api.SEARCH_ALL_ENDPOINT),
         body=HttpClientError(content='boom'),
     )
     logger = logging.getLogger('enterprise.api_client.discovery')
     handler = MockLoggingHandler(level="ERROR")
     logger.addHandler(handler)
     with self.assertRaises(HttpClientError):
         self.api.get_catalog_results(
             content_filter_query='query',
             query_params={u'page': 2}
         )
     expected_message = ('Attempted to call course-discovery search/all/ endpoint with the following parameters: '
                         'content_filter_query: query, query_params: {}, traverse_pagination: False. '
                         'Failed to retrieve data from the catalog API. content -- [boom]').format({u'page': 2})
     assert handler.messages['error'][0] == expected_message
Esempio n. 28
0
    def test_authenticate_invalid_credentials(self):
        backend = TestClaBackend()
        credentials = {"username": "******", "password": "******"}

        connection = mock.MagicMock()
        connection.oauth2.access_token.post.side_effect = HttpClientError(
            content='{"error": "invalid grant"}')
        self.mocked_get_auth_connection.return_value = connection

        self.assertEqual(backend.authenticate(**credentials), None)
        self.assertEqual(self.mocked_get_auth_connection.called, True)
        connection.oauth2.access_token.post.assert_called_with({
            "client_id":
            base.DEFAULT_ZONE_PROFILE["CLIENT_ID"],
            "client_secret":
            base.DEFAULT_ZONE_PROFILE["CLIENT_SECRET"],
            "grant_type":
            "password",
            "username":
            credentials["username"],
            "password":
            credentials["password"],
        })
Esempio n. 29
0
 def test_non_existent_get_buyer(self, slumber):
     slumber.generic.buyer.get_object_or_404.side_effect = HttpClientError(
         response=self.create_error_response())
     buyer = client.get_buyer('something-that-does-not-exist')
     assert 'errors' in buyer
Esempio n. 30
0
 def test_invalid_json_response(self, fake_log, slumber):
     slumber.generic.buyer.get_object_or_404.side_effect = HttpClientError(
         response=self.create_error_response(content='<not valid json>'))
     with self.assertRaises(ValueError):
         client.get_buyer('catastrophic-non-json-error')
     assert fake_log.error.called, 'expected response to be logged'
Esempio n. 31
0
 def test_verify_alpha_pin(self, slumber):
     slumber.generic.verify_pin.post.side_effect = HttpClientError(
         response=self.create_error_response(
             content={'pin': ['PIN_ONLY_NUMBERS']}))
     assert 'pin' in client.verify_pin(self.uuid, 'lame')['errors']
Esempio n. 32
0
    def test_notice_failure(self):
        post = self.slumber.provider.reference.notices.post
        post.side_effect = HttpClientError('bad stuff')

        res = self.success()
        eq_(res.status_code, 400)