Esempio n. 1
0
    def send_xapi_statements(self, lrs_configuration, days):
        """
        Send xAPI analytics data of the enterprise learners to the given LRS.

        Arguments:
            lrs_configuration (XAPILRSConfiguration): Configuration object containing LRS configurations
                of the LRS where to send xAPI  learner analytics.
            days (int): Include course enrollment of this number of days.
        """
        persistent_course_grades = self.get_course_completions(
            lrs_configuration.enterprise_customer, days)
        users = self.prefetch_users(persistent_course_grades)
        course_overviews = self.prefetch_courses(persistent_course_grades)

        for persistent_course_grade in persistent_course_grades:
            try:
                user = users.get(persistent_course_grade.user_id)
                course_overview = course_overviews.get(
                    persistent_course_grade.course_id)
                course_grade = CourseGradeFactory().read(
                    user, course_key=persistent_course_grade.course_id)
                send_course_completion_statement(lrs_configuration, user,
                                                 course_overview, course_grade)
            except ClientError:
                LOGGER.exception(
                    'Client error while sending course completion to xAPI for'
                    ' enterprise customer {enterprise_customer}.'.format(
                        enterprise_customer=lrs_configuration.
                        enterprise_customer.name))
Esempio n. 2
0
    def send_xapi_statements(self, lrs_configuration, days):
        """
        Send xAPI analytics data of the enterprise learners to the given LRS.

        Arguments:
            lrs_configuration (XAPILRSConfiguration): Configuration object containing LRS configurations
                of the LRS where to send xAPI  learner analytics.
            days (int): Include course enrollment of this number of days.
        """
        persistent_course_grades = self.get_course_completions(
            lrs_configuration.enterprise_customer, days)
        users = self.prefetch_users(persistent_course_grades)
        course_overviews = self.prefetch_courses(persistent_course_grades)

        for persistent_course_grade in persistent_course_grades:
            error_message = None
            user = users.get(persistent_course_grade.user_id)
            course_overview = course_overviews.get(
                persistent_course_grade.course_id)
            course_grade = CourseGradeFactory().read(
                user, course_key=persistent_course_grade.course_id)
            xapi_transmission_queryset = XAPILearnerDataTransmissionAudit.objects.filter(
                user=user, course_id=persistent_course_grade.course_id)
            if not xapi_transmission_queryset.exists():
                LOGGER.warning(
                    'XAPILearnerDataTransmissionAudit object does not exist for user: {username}, course: '
                    '{course_id} so skipping the course completion statement to xapi.'
                )
                continue
            try:
                send_course_completion_statement(lrs_configuration, user,
                                                 course_overview, course_grade)
            except ClientError:
                error_message = 'Client error while sending course completion to xAPI for ' \
                                'enterprise customer: {enterprise_customer}, user: {username} ' \
                                'and course: {course_id}'.format(
                                    enterprise_customer=lrs_configuration.enterprise_customer.name,
                                    username=user.username if user else '',
                                    course_id=persistent_course_grade.course_id
                                )
                LOGGER.exception(error_message)
                status = 500
            else:
                LOGGER.info(
                    'Successfully sent course completion to xAPI for user: {username} for course: {course_id}'
                    .format(username=user.username if user else '',
                            course_id=persistent_course_grade.course_id))
                status = 200
            fields = {'status': status, 'error_message': error_message}
            if status == 200:
                fields.update({
                    'grade': course_grade.percent,
                    'timestamp': course_grade.passed_timestamp
                })
            xapi_transmission_queryset.update(**fields)
Esempio n. 3
0
    def test_send_course_completion_statement(self):
        """
        Verify that send_course_completion_statement sends xAPI statement to LRS.
        """
        send_course_completion_statement(
            self.x_api_lrs_config,
            self.user,
            self.course_overview,
            self.course_grade,
        )

        self.x_api_client.lrs.save_statement.assert_called()  # pylint: disable=no-member
Esempio n. 4
0
    def test_send_course_completion_statement(self, mock_get_user_social_auth,
                                              *args):  # pylint: disable=unused-argument
        """
        Verify that send_course_completion_statement sends xAPI statement to LRS.
        """
        mock_get_user_social_auth.return_value = self.mock_social_auth
        send_course_completion_statement(self.x_api_lrs_config, self.user,
                                         self.course_overview,
                                         self.course_grade, ContentType.COURSE,
                                         {
                                             'status': 500,
                                             'error_message': None
                                         })

        self.x_api_client.lrs.save_statement.assert_called()  # pylint: disable=no-member
Esempio n. 5
0
    def test_send_course_completion_statement(self, mock_catalog_integration,
                                              *args):  # pylint: disable=unused-argument
        """
        Verify that send_course_completion_statement sends xAPI statement to LRS.
        """
        mock_integration_config = mock.Mock(enabled=True)
        mock_catalog_integration.current.return_value = mock_integration_config
        send_course_completion_statement(
            self.x_api_lrs_config,
            self.user,
            self.course_overview,
            self.course_grade,
        )

        self.x_api_client.lrs.save_statement.assert_called()  # pylint: disable=no-member
Esempio n. 6
0
    def send_xapi_statements(self, lrs_configuration, days):
        """
        Send xAPI analytics data of the enterprise learners to the given LRS.

        Arguments:
            lrs_configuration (XAPILRSConfiguration): Configuration object containing LRS configurations
                of the LRS where to send xAPI  learner analytics.

            days (Numeric):  Deprecated.  Original implementation utilized a "days" parameter to limit
                the number of enrollments transmitted, but this proved to be more problematic than helpful.
        """
        enterprise_course_enrollments = self.get_enterprise_course_enrollments(lrs_configuration.enterprise_customer)
        enterprise_enrollment_ids = self.get_enterprise_enrollment_ids(enterprise_course_enrollments)
        xapi_transmission_queryset = self.get_xapi_transmission_queryset(enterprise_enrollment_ids)
        pertinent_enrollment_ids = self.get_pertinent_enrollment_ids(xapi_transmission_queryset)
        pertinent_enrollments = self.get_pertinent_enrollments(enterprise_course_enrollments, pertinent_enrollment_ids)
        enrollment_grades = self.get_course_completions(pertinent_enrollments)
        users = self.prefetch_users(enrollment_grades)
        course_overviews = self.prefetch_courses(enrollment_grades)
        course_catalog_client = get_course_catalog_api_service_client(site=lrs_configuration.enterprise_customer.site)

        for xapi_transmission in xapi_transmission_queryset:

            object_type = self.get_object_type(xapi_transmission)

            try:
                course_grade = enrollment_grades[xapi_transmission.enterprise_course_enrollment_id]
            except KeyError:
                continue

            user = users.get(course_grade.user_id)
            courserun_id = six.text_type(course_grade.course_id)
            course_overview = course_overviews.get(course_grade.course_id)
            course_run_identifiers = course_catalog_client.get_course_run_identifiers(courserun_id)
            course_overview.course_key = course_run_identifiers['course_key']
            course_overview.course_uuid = course_run_identifiers['course_uuid']

            default_error_message = 'Days argument has been deprecated.  Value: {days}'.format(days=days)
            response_fields = {'status': 500, 'error_message': default_error_message}
            response_fields = send_course_completion_statement(
                lrs_configuration,
                user,
                course_overview,
                course_grade,
                object_type,
                response_fields
            )

            if is_success_response(response_fields):
                self.save_xapi_learner_data_transmission_audit(
                    xapi_transmission,
                    course_grade.percent_grade,
                    1,
                    course_grade.passed_timestamp,
                    response_fields.get('status'),
                    response_fields.get('error_message')
                )
    def send_xapi_statements(self, lrs_configuration, days):
        """
        Send xAPI analytics data of the enterprise learners to the given LRS.

        Arguments:
            lrs_configuration (XAPILRSConfiguration): Configuration object containing LRS configurations
                of the LRS where to send xAPI  learner analytics.
            days (int): Include course enrollment of this number of days.
        """
        persistent_course_grades = self.get_course_completions(
            lrs_configuration.enterprise_customer, days)
        users = self.prefetch_users(persistent_course_grades)
        course_overviews = self.prefetch_courses(persistent_course_grades)
        LOGGER.info(
            '[Integrated Channel][xAPI] Found %s course completion for enterprise customer: [%s] during last %s days',
            len(persistent_course_grades),
            lrs_configuration.enterprise_customer,
            days,
        )

        for persistent_course_grade in persistent_course_grades:
            error_message = None
            user = users.get(persistent_course_grade.user_id)
            course_overview = course_overviews.get(
                persistent_course_grade.course_id)
            course_grade = CourseGradeFactory().read(
                user, course_key=persistent_course_grade.course_id)
            xapi_transmission_queryset = XAPILearnerDataTransmissionAudit.objects.filter(
                user=user,
                course_id=persistent_course_grade.course_id,
                course_completed=0)
            if not xapi_transmission_queryset.exists():
                LOGGER.warning(
                    'XAPILearnerDataTransmissionAudit object does not exist for enterprise customer: '
                    '{enterprise_customer}, user: {username}, course: {course_id}.  Skipping transmission '
                    'of course completion statement to the configured LRS endpoint.  This is likely because '
                    'a corresponding course enrollment statement has not yet been transmitted.'
                    .format(
                        enterprise_customer=lrs_configuration.
                        enterprise_customer.name,
                        username=user.username if user else 'User Unavailable',
                        course_id=persistent_course_grade.course_id))
                continue
            fields = {'status': 500, 'error_message': None}
            try:
                response = send_course_completion_statement(
                    lrs_configuration, user, course_overview, course_grade)
            except ClientError:
                error_message = 'Client error while sending course completion to xAPI for ' \
                                'enterprise customer: {enterprise_customer}, user: {username} ' \
                                'and course: {course_id}'.format(
                                    enterprise_customer=lrs_configuration.enterprise_customer.name,
                                    username=user.username if user else 'User Unavailable',
                                    course_id=persistent_course_grade.course_id
                                )
                LOGGER.exception(error_message)
                fields.update({'error_message': error_message})
            else:
                status = response.response.status
                fields.update({'status': status})
                if response.success:
                    LOGGER.info(
                        'Successfully sent xAPI course completion for user: {username} for course: {course_id}'
                        .format(username=user.username
                                if user else 'User Unavailable',
                                course_id=persistent_course_grade.course_id))
                    fields.update({
                        'grade':
                        course_grade.percent,
                        'course_completed':
                        1,
                        'completed_timestamp':
                        persistent_course_grade.modified
                    })
                else:
                    LOGGER.warning(
                        'Unexpected xAPI response received for user: {username} for course: {course_id}.  Please '
                        'reveiew the xAPI learner data transmission audit log for details'
                        .format(username=user.username
                                if user else 'User Unavailable',
                                course_id=persistent_course_grade.course_id))
                    fields.update({'error_message': response.data})
            xapi_transmission_queryset.update(**fields)