def _mock_commerce_api(self, status, body=None):
        self.assertTrue(httpretty.is_enabled(), 'httpretty must be enabled to mock Commerce API calls.')

        body = body or {}
        url = '{}/courses/{}/'.format(get_lms_commerce_api_url().rstrip('/'), self.course.id)
        httpretty.register_uri(httpretty.PUT, url, status=status, body=json.dumps(body),
                               content_type=JSON)
Ejemplo n.º 2
0
    def _mock_commerce_api(self, status, body=None):
        self.assertTrue(httpretty.is_enabled(), 'httpretty must be enabled to mock Commerce API calls.')

        body = body or {}
        url = '{}/courses/{}/'.format(get_lms_commerce_api_url().rstrip('/'), self.course.id)
        httpretty.register_uri(httpretty.PUT, url, status=status, body=json.dumps(body),
                               content_type=JSON)
Ejemplo n.º 3
0
    def publish(self, course, access_token=None):
        """ Publish course commerce data to LMS.

        Uses the Commerce API to publish course modes, prices, and SKUs to LMS. Uses
        CreditCourse API endpoints to publish CreditCourse data to LMS when necessary.

        Arguments:
            course (Course): Course to be published.

        Keyword Arguments:
            access_token (str): Access token used when publishing CreditCourse data to the LMS.

        Returns:
            None, if publish operation succeeded; otherwise, error message.
        """

        course_id = course.id
        error_message = _(u'Failed to publish commerce data for {course_id} to LMS.').format(
            course_id=course_id
        )

        commerce_api_url = get_lms_commerce_api_url()
        if not commerce_api_url:
            logger.error('Commerce API URL is not set. Commerce data will not be published!')
            return error_message

        name = course.name
        verification_deadline = self.get_course_verification_deadline(course)
        modes = [self.serialize_seat_for_commerce_api(seat) for seat in course.seat_products]

        has_credit = 'credit' in [mode['name'] for mode in modes]
        if has_credit:
            try:
                self._publish_creditcourse(course_id, access_token)
                logger.info(u'Successfully published CreditCourse for [%s] to LMS.', course_id)
            except SlumberHttpBaseException as e:
                # Note that %r is used to log the repr() of the response content, which may sometimes
                # contain non-ASCII Unicode. We don't know (or want to guess) the encoding, so using %r will log the
                # raw bytes of the message, freeing us from the possibility of encoding errors.
                logger.exception(
                    u'Failed to publish CreditCourse for [%s] to LMS. Status was [%d]. Body was %r.',
                    course_id,
                    e.response.status_code,
                    e.content
                )
                return error_message
            except Exception:  # pylint: disable=broad-except
                logger.exception(u'Failed to publish CreditCourse for [%s] to LMS.', course_id)
                return error_message

        data = {
            'id': course_id,
            'name': name,
            'verification_deadline': verification_deadline,
            'modes': modes,
        }

        url = '{}/courses/{}/'.format(commerce_api_url.rstrip('/'), course_id)

        headers = {
            'Content-Type': 'application/json',
            'X-Edx-Api-Key': settings.EDX_API_KEY
        }

        try:
            response = requests.put(url, data=json.dumps(data), headers=headers, timeout=self.timeout)
            status_code = response.status_code
            if status_code in (200, 201):
                logger.info(u'Successfully published commerce data for [%s].', course_id)
                return
            else:
                logger.error(u'Failed to publish commerce data for [%s] to LMS. Status was [%d]. Body was [%s].',
                             course_id, status_code, response.content)

                return self._parse_error(response, error_message)

        except Exception:  # pylint: disable=broad-except
            logger.exception(u'Failed to publish commerce data for [%s] to LMS.', course_id)

        return error_message
Ejemplo n.º 4
0
    def publish(self, course, access_token=None):
        """ Publish course commerce data to LMS.

        Uses the Commerce API to publish course modes, prices, and SKUs to LMS. Uses
        CreditCourse API endpoints to publish CreditCourse data to LMS when necessary.

        Arguments:
            course (Course): Course to be published.

        Keyword Arguments:
            access_token (str): Access token used when publishing CreditCourse data to the LMS.

        Returns:
            None, if publish operation succeeded; otherwise, error message.
        """

        course_id = course.id
        error_message = _(u'Failed to publish commerce data for {course_id} to LMS.').format(
            course_id=course_id
        )

        commerce_api_url = get_lms_commerce_api_url()
        if not commerce_api_url:
            logger.error('Commerce API URL is not set. Commerce data will not be published!')
            return error_message

        name = course.name
        verification_deadline = self.get_course_verification_deadline(course)
        modes = [self.serialize_seat_for_commerce_api(seat) for seat in course.seat_products]

        has_credit = 'credit' in [mode['name'] for mode in modes]
        if has_credit:
            try:
                self._publish_creditcourse(course_id, access_token)
                logger.info(u'Successfully published CreditCourse for [%s] to LMS.', course_id)
            except SlumberHttpBaseException as e:
                # Note that %r is used to log the repr() of the response content, which may sometimes
                # contain non-ASCII Unicode. We don't know (or want to guess) the encoding, so using %r will log the
                # raw bytes of the message, freeing us from the possibility of encoding errors.
                logger.exception(
                    u'Failed to publish CreditCourse for [%s] to LMS. Status was [%d]. Body was %r.',
                    course_id,
                    e.response.status_code,
                    e.content
                )
                return error_message
            except Exception:  # pylint: disable=broad-except
                logger.exception(u'Failed to publish CreditCourse for [%s] to LMS.', course_id)
                return error_message

        data = {
            'id': course_id,
            'name': name,
            'verification_deadline': verification_deadline,
            'modes': modes,
        }

        url = '{}/courses/{}/'.format(commerce_api_url.rstrip('/'), course_id)

        headers = {
            'Content-Type': 'application/json',
            'X-Edx-Api-Key': settings.EDX_API_KEY
        }

        try:
            response = requests.put(url, data=json.dumps(data), headers=headers, timeout=self.timeout)
            status_code = response.status_code
            if status_code in (200, 201):
                logger.info(u'Successfully published commerce data for [%s].', course_id)
                return
            else:
                logger.error(u'Failed to publish commerce data for [%s] to LMS. Status was [%d]. Body was [%s].',
                             course_id, status_code, response.content)

                return self._parse_error(response, error_message)

        except Exception:  # pylint: disable=broad-except
            logger.exception(u'Failed to publish commerce data for [%s] to LMS.', course_id)

        return error_message