Example #1
0
    def emit_event(self, event_name):
        """
        Emits an event to explicitly track course enrollment and unenrollment.
        """

        try:
            context = contexts.course_context_from_course_id(self.course_id)
            assert(isinstance(self.course_id, CourseKey))
            data = {
                'user_id': self.user.id,
                'course_id': self.course_id.to_deprecated_string(),
                'mode': self.mode,
            }

            with tracker.get_tracker().context(event_name, context):
                tracker.emit(event_name, data)

                if settings.FEATURES.get('SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY:
                    tracking_context = tracker.get_tracker().resolve_context()
                    analytics.track(self.user_id, event_name, {
                        'category': 'conversion',
                        'label': self.course_id.to_deprecated_string(),
                        'org': self.course_id.org,
                        'course': self.course_id.course,
                        'run': self.course_id.run,
                        'mode': self.mode,
                    }, context={
                        'Google Analytics': {
                            'clientId': tracking_context.get('client_id')
                        }
                    })

        except:  # pylint: disable=bare-except
            if event_name and self.course_id:
                log.exception('Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id)
Example #2
0
    def process_request(self, request):
        """
        Add a user's tags to the tracking event context.
        """
        match = COURSE_REGEX.match(request.build_absolute_uri())
        course_id = None
        if match:
            course_id = match.group('course_id')

        context = {}

        if course_id:
            context['course_id'] = course_id

            if request.user.is_authenticated():
                context['course_user_tags'] = dict(
                    UserCourseTag.objects.filter(
                        user=request.user.pk,
                        course_id=course_id
                    ).values_list('key', 'value')
                )
            else:
                context['course_user_tags'] = {}

        tracker.get_tracker().enter_context(
            self.CONTEXT_NAME,
            context
        )
Example #3
0
    def process_request(self, request):
        """
        Add a user's tags to the tracking event context.
        """
        match = COURSE_REGEX.match(request.path)
        course_key = None
        if match:
            course_key = match.group('course_id')
            try:
                course_key = CourseKey.from_string(course_key)
            except InvalidKeyError:
                course_key = None

        context = {}

        if course_key:
            try:
                context['course_id'] = course_key.to_deprecated_string()
            except AttributeError:
                context['course_id'] = unicode(course_key)

            if request.user.is_authenticated():
                context['course_user_tags'] = dict(
                    UserCourseTag.objects.filter(
                        user=request.user.pk,
                        course_id=course_key,
                    ).values_list('key', 'value')
                )
            else:
                context['course_user_tags'] = {}

        tracker.get_tracker().enter_context(
            self.CONTEXT_NAME,
            context
        )
Example #4
0
    def process_request(self, request):
        """
        Add a user's tags to the tracking event context.
        """
        match = COURSE_REGEX.match(request.build_absolute_uri())
        course_id = None
        if match:
            course_id = match.group('course_id')
            try:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
            except InvalidKeyError:
                course_id = None
                course_key = None

        context = {}

        if course_id:
            context['course_id'] = course_id

            if request.user.is_authenticated():
                context['course_user_tags'] = dict(
                    UserCourseTag.objects.filter(
                        user=request.user.pk,
                        course_id=course_key,
                    ).values_list('key', 'value')
                )
            else:
                context['course_user_tags'] = {}

        tracker.get_tracker().enter_context(
            self.CONTEXT_NAME,
            context
        )
Example #5
0
    def enter_request_context(self, request):
        """
        Extract information from the request and add it to the tracking
        context.

        The following fields are injected into the context:

        * session - The Django session key that identifies the user's session.
        * user_id - The numeric ID for the logged in user.
        * username - The username of the logged in user.
        * ip - The IP address of the client.
        * host - The "SERVER_NAME" header, which should be the name of the server running this code.
        * agent - The client browser identification string.
        * path - The path part of the requested URL.
        * client_id - The unique key used by Google Analytics to identify a user
        """
        context = {
            "session": self.get_session_key(request),
            "user_id": self.get_user_primary_key(request),
            "username": self.get_username(request),
        }
        for header_name, context_key in META_KEY_TO_CONTEXT_KEY.iteritems():
            context[context_key] = request.META.get(header_name, "")

        # Google Analytics uses the clientId to keep track of unique visitors. A GA cookie looks like
        # this: _ga=GA1.2.1033501218.1368477899. The clientId is this part: 1033501218.1368477899.
        google_analytics_cookie = request.COOKIES.get("_ga")
        if google_analytics_cookie is None:
            context["client_id"] = None
        else:
            context["client_id"] = ".".join(google_analytics_cookie.split(".")[2:])

        context.update(contexts.course_context_from_url(request.build_absolute_uri()))

        tracker.get_tracker().enter_context(CONTEXT_NAME, context)
    def process_response(self, request, response):
        """Exit the context if it exists."""
        try:
            tracker.get_tracker().exit_context(CONTEXT_NAME)
        except Exception:  # pylint: disable=broad-except
            pass

        # Set spam query string into cookie
        spam = request.GET.get('spam')
        if spam:
            response.set_cookie('spam', spam)

        # track session changed 
        try:
            origin_session = request.COOKIES.get('sessionid')
            if origin_session and request.session.session_key and request.session.session_key != origin_session:
                session_md5 = hashlib.md5()
                session_md5.update(request.session.session_key)
                origin_session_md5 = hashlib.md5()
                origin_session_md5.update(origin_session)
                event = {
                    'changed_session': session_md5.hexdigest(),
                    'origin_session': origin_session_md5.hexdigest(),
                }
                views.server_track(request, request.META['PATH_INFO'], event)
        except Exception, e:
            pass
Example #7
0
def user_track(request):
    """
    Log when POST call to "event" URL is made by a user. Uses request.REQUEST
    to allow for GET calls.

    GET or POST call should provide "event_type", "event", and "page" arguments.
    """
    try:  # TODO: Do the same for many of the optional META parameters
        username = request.user.username
    except:
        username = "******"

    page = request.REQUEST['page']

    with eventtracker.get_tracker().context('edx.course.browser', contexts.course_context_from_url(page)):
        context = eventtracker.get_tracker().resolve_context()
        event = {
            "username": username,
            "session": context.get('session', ''),
            "ip": _get_request_header(request, 'REMOTE_ADDR'),
            "event_source": "browser",
            "event_type": request.REQUEST['event_type'],
            "event": request.REQUEST['event'],
            "agent": _get_request_header(request, 'HTTP_USER_AGENT'),
            "page": page,
            "time": datetime.datetime.utcnow(),
            "host": _get_request_header(request, 'SERVER_NAME'),
            "context": context,
        }

    log_event(event)

    return HttpResponse('success')
Example #8
0
    def enter_request_context(self, request):
        """
        Extract information from the request and add it to the tracking
        context.

        The following fields are injected in to the context:

        * session - The Django session key that identifies the user's session.
        * user_id - The numeric ID for the logged in user.
        * username - The username of the logged in user.
        * ip - The IP address of the client.
        * host - The "SERVER_NAME" header, which should be the name of the server running this code.
        * agent - The client browser identification string.
        * path - The path part of the requested URL.
        """
        context = {
            'session': self.get_session_key(request),
            'user_id': self.get_user_primary_key(request),
            'username': self.get_username(request),
        }
        for header_name, context_key in META_KEY_TO_CONTEXT_KEY.iteritems():
            context[context_key] = request.META.get(header_name, '')

        context.update(contexts.course_context_from_url(request.build_absolute_uri()))

        tracker.get_tracker().enter_context(
            CONTEXT_NAME,
            context
        )
Example #9
0
    def emit_event(self, event_name):
        """
        Emits an event to explicitly track course enrollment and unenrollment.
        """

        try:
            context = contexts.course_context_from_course_id(self.course_id)
            assert isinstance(self.course_id, CourseKey)
            data = {"user_id": self.user.id, "course_id": self.course_id.to_deprecated_string(), "mode": self.mode}

            with tracker.get_tracker().context(event_name, context):
                tracker.emit(event_name, data)

                if settings.FEATURES.get("SEGMENT_IO_LMS") and settings.SEGMENT_IO_LMS_KEY:
                    tracking_context = tracker.get_tracker().resolve_context()
                    analytics.track(
                        self.user_id,
                        event_name,
                        {
                            "category": "conversion",
                            "label": self.course_id.to_deprecated_string(),
                            "org": self.course_id.org,
                            "course": self.course_id.course,
                            "run": self.course_id.run,
                            "mode": self.mode,
                        },
                        context={"Google Analytics": {"clientId": tracking_context.get("client_id")}},
                    )

        except:  # pylint: disable=bare-except
            if event_name and self.course_id:
                log.exception(
                    "Unable to emit event %s for user %s and course %s", event_name, self.user.username, self.course_id
                )
Example #10
0
    def process_response(self, _request, response):
        """Exit the context if it exists."""
        try:
            tracker.get_tracker().exit_context(CONTEXT_NAME)
        except Exception:  # pylint: disable=broad-except
            pass

        return response
Example #11
0
    def process_response(self, request, response):  # pylint: disable=unused-argument
        """Exit the context if it exists."""
        try:
            tracker.get_tracker().exit_context(self.CONTEXT_NAME)
        except:  # pylint: disable=bare-except
            pass

        return response
Example #12
0
 def enter_course_context(self, request):
     """
     Extract course information from the request and add it to the
     tracking context.
     """
     tracker.get_tracker().enter_context(
         COURSE_CONTEXT_NAME,
         contexts.course_context_from_url(request.build_absolute_uri())
     )
    def get_context_for_request(self, request):
        """Extract the generated event tracking context for the given request."""
        self.track_middleware.process_request(request)
        try:
            captured_context = tracker.get_tracker().resolve_context()
        finally:
            self.track_middleware.process_response(request, None)

        self.assertEquals(tracker.get_tracker().resolve_context(), {})

        return captured_context
 def test_request_in_course_context(self):
     request = self.request_factory.get('/courses/test_org/test_course/test_run/foo')
     self.track_middleware.process_request(request)
     self.assertEquals(
         tracker.get_tracker().resolve_context(),
         {
             'course_id': 'test_org/test_course/test_run',
             'org_id': 'test_org'
         }
     )
     self.track_middleware.process_response(request, None)
     self.assertEquals(
         tracker.get_tracker().resolve_context(),
         {}
     )
Example #15
0
def _track_notification_sent(message, context):
    """
    Send analytics event for a sent email
    """
    properties = {
        'app_label': 'discussion',
        'name': 'responsenotification',  # This is 'Campaign' in GA
        'language': message.language,
        'uuid': unicode(message.uuid),
        'send_uuid': unicode(message.send_uuid),
        'thread_id': context['thread_id'],
        'course_id': unicode(context['course_id']),
        'thread_created_at': date.deserialize(context['thread_created_at']),
        'nonInteraction': 1,
    }
    tracking_context = {
        'host': context['site'].domain,
        'path': '/',  # make up a value, in order to allow the host to be passed along.
    }
    # The event used to specify the user_id as being the recipient of the email (i.e. the thread_author_id).
    # This has the effect of interrupting the actual chain of events for that author, if any, while the
    # email-sent event should really be associated with the sender, since that is what triggers the event.
    with tracker.get_tracker().context(properties['app_label'], tracking_context):
        segment.track(
            user_id=context['thread_author_id'],
            event_name='edx.bi.email.sent',
            properties=properties
        )
Example #16
0
    def _track_reverification_events(self, event_name, user_id, course_id, checkpoint):  # pylint: disable=invalid-name
        """Track re-verification events for a user against a reverification
        checkpoint of a course.

        Arguments:
            event_name (str): Name of event being tracked
            user_id (str): The ID of the user
            course_id (unicode): ID associated with the course
            checkpoint (str): Checkpoint name

        Returns:
            None
        """
        log.info(
            u"In-course reverification: event %s occurred for user '%s' in course '%s' at checkpoint '%s'",
            event_name, user_id, course_id, checkpoint
        )

        if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
            tracking_context = tracker.get_tracker().resolve_context()
            analytics.track(
                user_id,
                event_name,
                {
                    'category': "verification",
                    'label': unicode(course_id),
                    'checkpoint': checkpoint
                },
                context={
                    'Google Analytics': {
                        'clientId': tracking_context.get('client_id')
                    }
                }
            )
Example #17
0
    def _track_reverification_events(self, event_name, user_id, course_id, checkpoint):  # pylint: disable=invalid-name
        """Track re-verification events for user against course checkpoints

        Arguments:
            user_id (str): The ID of the user generting the certificate.
            course_id (unicode):  id associated with the course
            checkpoint (str):  checkpoint name
        Returns:
            None

        """
        if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
            tracking_context = tracker.get_tracker().resolve_context()
            analytics.track(
                user_id,
                event_name,
                {
                    'category': "verification",
                    'label': unicode(course_id),
                    'checkpoint': checkpoint
                },
                context={
                    'Google Analytics': {
                        'clientId': tracking_context.get('client_id')
                    }
                }
            )
Example #18
0
def server_track(request, event_type, event, page=None):
    """
    Log events related to server requests.

    Handle the situation where the request may be NULL, as may happen with management commands.
    """
    if event_type.startswith("/event_logs") and request.user.is_staff:
        return  # don't log

    try:
        username = request.user.username
    except:
        username = "******"

    # define output:
    event = {
        "username": username,
        "ip": _get_request_header(request, 'REMOTE_ADDR'),
        "event_source": "server",
        "event_type": event_type,
        "event": event,
        "agent": _get_request_header(request, 'HTTP_USER_AGENT'),
        "page": page,
        "time": datetime.datetime.now(UTC),
        "host": _get_request_header(request, 'SERVER_NAME'),
        "context": eventtracker.get_tracker().resolve_context(),
    }

    log_event(event)
Example #19
0
def create_tracking_context(user):
    """ Assembles attributes from user and request objects to be sent along
    in ecommerce api calls for tracking purposes. """
    return {
        'lms_user_id': user.id,
        'lms_client_id': tracker.get_tracker().resolve_context().get('client_id')
    }
Example #20
0
def server_track(request, event_type, event, page=None):
    """Log events related to server requests."""
    try:
        username = request.user.username
    except:
        username = "******"

    try:
        agent = request.META['HTTP_USER_AGENT']
    except:
        agent = ''

    event = {
        "username": username,
        "ip": request.META['REMOTE_ADDR'],
        "event_source": "server",
        "event_type": event_type,
        "event": event,
        "agent": agent,
        "page": page,
        "time": datetime.datetime.now(UTC),
        "host": request.META['SERVER_NAME'],
        "context": eventtracker.get_tracker().resolve_context(),
    }

    if event_type.startswith("/event_logs") and request.user.is_staff:
        return  # don't log

    log_event(event)
Example #21
0
def login_analytics(strategy, auth_entry, *args, **kwargs):
    """ Sends login info to Segment """

    event_name = None
    if auth_entry == AUTH_ENTRY_LOGIN:
        event_name = 'edx.bi.user.account.authenticated'
    elif auth_entry in [AUTH_ENTRY_ACCOUNT_SETTINGS]:
        event_name = 'edx.bi.user.account.linked'

    if event_name is not None and hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY:
        tracking_context = tracker.get_tracker().resolve_context()
        analytics.track(
            kwargs['user'].id,
            event_name,
            {
                'category': "conversion",
                'label': None,
                'provider': getattr(kwargs['backend'], 'name')
            },
            context={
                'ip': tracking_context.get('ip'),
                'Google Analytics': {
                    'clientId': tracking_context.get('client_id')
                }
            }
        )
Example #22
0
def login_analytics(*args, **kwargs):
    """ Sends login info to Segment.io """
    event_name = None

    action_to_event_name = {
        'is_login': '******',
        'is_dashboard': 'edx.bi.user.account.linked',
        'is_profile': 'edx.bi.user.account.linked',
    }

    # Note: we assume only one of the `action` kwargs (is_dashboard, is_login) to be
    # `True` at any given time
    for action in action_to_event_name.keys():
        if kwargs.get(action):
            event_name = action_to_event_name[action]

    if event_name is not None:
        registration_course_id = kwargs['request'].session.get('registration_course_id')
        tracking_context = tracker.get_tracker().resolve_context()
        analytics.track(
            kwargs['user'].id,
            event_name,
            {
                'category': "conversion",
                'label': registration_course_id,
                'provider': getattr(kwargs['backend'], 'name')
            },
            context={
                'Google Analytics': {
                    'clientId': tracking_context.get('client_id') 
                }
            }
        )
Example #23
0
    def test_user_track(self):
        request = self.request_factory.get('/event', {
            'page': self.url_with_course,
            'event_type': sentinel.event_type,
            'event': {}
        })
        with tracker.get_tracker().context('edx.request', {'session': sentinel.session}):
            views.user_track(request)

        expected_event = {
            'username': '******',
            'session': sentinel.session,
            'ip': '127.0.0.1',
            'event_source': 'browser',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': self.url_with_course,
            'time': expected_time,
            'host': 'testserver',
            'context': {
                'course_id': 'foo/bar/baz',
                'org_id': 'foo',
            },
        }
        self.mock_tracker.send.assert_called_once_with(expected_event)
Example #24
0
def _track_message_sent(site, user, msg):
    properties = {
        'site': site.domain,
        'app_label': msg.app_label,
        'name': msg.name,
        'language': msg.language,
        'uuid': unicode(msg.uuid),
        'send_uuid': unicode(msg.send_uuid),
        'nonInteraction': 1,
    }
    course_ids = msg.context.get('course_ids', [])
    properties['num_courses'] = len(course_ids)
    if len(course_ids) > 0:
        properties['course_ids'] = course_ids[:10]
        properties['primary_course_id'] = course_ids[0]

    tracking_context = {
        'host': site.domain,
        'path': '/',  # make up a value, in order to allow the host to be passed along.
    }
    # I wonder if the user of this event should be the recipient, as they are not the ones
    # who took an action.  Rather, the system is acting, and they are the object.
    # Admittedly that may be what 'nonInteraction' is meant to address.  But sessionization may
    # get confused by these events if they're attributed in this way, because there's no way for
    # this event to get context that would match with what the user might be doing at the moment.
    # But the events do show up in GA being joined up with existing sessions (i.e. within a half
    # hour in the past), so they don't always break sessions.  Not sure what happens after these.
    # We can put the recipient_user_id into the properties, and then export as a custom dimension.
    with tracker.get_tracker().context(msg.app_label, tracking_context):
        segment.track(
            user_id=user.id,
            event_name='edx.bi.email.sent',
            properties=properties,
        )
Example #25
0
def _track_update_email_opt_in(user_id, organization, opt_in):
    """Track an email opt-in preference change.

    Arguments:
        user_id (str): The ID of the user making the preference change.
        organization (str): The organization whose emails are being opted into or out of by the user.
        opt_in (bool): Whether the user has chosen to opt-in to emails from the organization.

    Returns:
        None

    """
    event_name = 'edx.bi.user.org_email.opted_in' if opt_in else 'edx.bi.user.org_email.opted_out'
    tracking_context = tracker.get_tracker().resolve_context()

    analytics.track(
        user_id,
        event_name,
        {
            'category': 'communication',
            'label': organization
        },
        context={
            'ip': tracking_context.get('ip'),
            'Google Analytics': {
                'clientId': tracking_context.get('client_id')
            }
        }
    )
Example #26
0
def _emit_event(name, context, data):
    """
    Do the actual integration into the event-tracker
    """

    try:
        if context:
            # try to parse out the org_id from the course_id
            if 'course_id' in context:
                try:
                    course_key = CourseKey.from_string(context['course_id'])
                    context['org_id'] = course_key.org
                except InvalidKeyError:
                    # leave org_id blank
                    pass

            with tracker.get_tracker().context(name, context):
                tracker.emit(name, data)
        else:
            # if None is passed in then we don't construct the 'with' context stack
            tracker.emit(name, data)
    except KeyError:
        # This happens when a default tracker has not been registered by the host application
        # aka LMS. This is normal when running unit tests in isolation.
        log.warning(
            'Analytics tracker not properly configured. '
            'If this message appears in a production environment, please investigate'
        )
Example #27
0
def server_track(request, event_type, event, page=None):
    """
    Log events related to server requests.

    Handle the situation where the request may be NULL, as may happen with management commands.
    """
    if event_type.startswith("/event_logs") and request.user.is_staff:
        return  # don't log

    try:
        username = request.user.username
    except:
        username = "******"

    # define output:
    event = {
        "username": username,
        "ip": _get_request_ip(request),
        "referer": _get_request_header(request, 'HTTP_REFERER'),
        "accept_language": _get_request_header(request, 'HTTP_ACCEPT_LANGUAGE'),
        "event_source": "server",
        "event_type": event_type,
        "event": event,
        "agent": _get_request_header(request, 'HTTP_USER_AGENT').decode('latin1'),
        "page": page,
        "time": datetime.datetime.utcnow().replace(tzinfo=pytz.utc),
        "host": _get_request_header(request, 'SERVER_NAME'),
        "context": eventtracker.get_tracker().resolve_context(),
    }

    # Some duplicated fields are passed into event-tracking via the context by track.middleware.
    # Remove them from the event here since they are captured elsewhere.
    shim.remove_shim_context(event)

    log_event(event)
Example #28
0
 def _emit_grade_calculated_event(grade):
     """
     Emits an edx.grades.subsection.grade_calculated event
     with data from the passed grade.
     """
     # TODO: remove this context manager after completion of AN-6134
     event_name = u'edx.grades.subsection.grade_calculated'
     context = contexts.course_context_from_course_id(grade.course_id)
     with tracker.get_tracker().context(event_name, context):
         tracker.emit(
             event_name,
             {
                 'user_id': unicode(grade.user_id),
                 'course_id': unicode(grade.course_id),
                 'block_id': unicode(grade.usage_key),
                 'course_version': unicode(grade.course_version),
                 'weighted_total_earned': grade.earned_all,
                 'weighted_total_possible': grade.possible_all,
                 'weighted_graded_earned': grade.earned_graded,
                 'weighted_graded_possible': grade.possible_graded,
                 'first_attempted': unicode(grade.first_attempted),
                 'subtree_edited_timestamp': unicode(grade.subtree_edited_timestamp),
                 'event_transaction_id': unicode(get_event_transaction_id()),
                 'event_transaction_type': unicode(get_event_transaction_type()),
                 'visible_blocks_hash': unicode(grade.visible_blocks_id),
             }
         )
Example #29
0
def user_track(request):
    """
    Log when POST call to "event" URL is made by a user.

    GET or POST call should provide "event_type", "event", and "page" arguments.
    """
    try:
        username = request.user.username
    except:
        username = "******"

    name = _get_request_value(request, 'event_type')
    data = _get_request_value(request, 'event', {})
    page = _get_request_value(request, 'page')

    if isinstance(data, six.string_types) and len(data) > 0:
        try:
            data = json.loads(data)
            _add_user_id_for_username(data)
        except ValueError:
            pass

    context_override = contexts.course_context_from_url(page)
    context_override['username'] = username
    context_override['event_source'] = 'browser'
    context_override['page'] = page

    with eventtracker.get_tracker().context('edx.course.browser', context_override):
        eventtracker.emit(name=name, data=data)

    return HttpResponse('success')
Example #30
0
def _track_user_login(user, request):
    """
    Sends a tracking event for a successful login.
    """
    if hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY:
        tracking_context = tracker.get_tracker().resolve_context()
        analytics.identify(
            user.id,
            {
                'email': request.POST['email'],
                'username': user.username
            },
            {
                # Disable MailChimp because we don't want to update the user's email
                # and username in MailChimp on every page load. We only need to capture
                # this data on registration/activation.
                'MailChimp': False
            }
        )

        analytics.track(
            user.id,
            "edx.bi.user.account.authenticated",
            {
                'category': "conversion",
                'label': request.POST.get('course_id'),
                'provider': None
            },
            context={
                'ip': tracking_context.get('ip'),
                'Google Analytics': {
                    'clientId': tracking_context.get('client_id')
                }
            }
        )
Example #31
0
def task_track(request_info, task_info, event_type, event, page=None):
    """
    Logs tracking information for events occuring within celery tasks.

    The `event_type` is a string naming the particular event being logged,
    while `event` is a dict containing whatever additional contextual information
    is desired.

    The `request_info` is a dict containing information about the original
    task request.  Relevant keys are `username`, `ip`, `agent`, and `host`.
    While the dict is required, the values in it are not, so that {} can be
    passed in.

    In addition, a `task_info` dict provides more information about the current
    task, to be stored with the `event` dict.  This may also be an empty dict.

    The `page` parameter is optional, and allows the name of the page to
    be provided.
    """

    # supplement event information with additional information
    # about the task in which it is running.
    full_event = dict(event, **task_info)

    # All fields must be specified, in case the tracking information is
    # also saved to the TrackingLog model.  Get values from the task-level
    # information, or just add placeholder values.
    with eventtracker.get_tracker().context('edx.course.task', contexts.course_context_from_url(page)):
        event = {
            "username": request_info.get('username', 'unknown'),
            "ip": request_info.get('ip', 'unknown'),
            "event_source": "task",
            "event_type": event_type,
            "event": full_event,
            "agent": request_info.get('agent', 'unknown'),
            "page": page,
            "time": datetime.datetime.utcnow().replace(tzinfo=pytz.utc),
            "host": request_info.get('host', 'unknown'),
            "context": eventtracker.get_tracker().resolve_context(),
        }

    log_event(event)
Example #32
0
    def enter_request_context(self, request):
        """
        Extract information from the request and add it to the tracking
        context.

        The following fields are injected into the context:

        * session - The Django session key that identifies the user's session.
        * user_id - The numeric ID for the logged in user.
        * username - The username of the logged in user.
        * ip - The IP address of the client.
        * host - The "SERVER_NAME" header, which should be the name of the server running this code.
        * agent - The client browser identification string.
        * path - The path part of the requested URL.
        * client_id - The unique key used by Google Analytics to identify a user
        """
        context = {
            'session': self.get_session_key(request),
            'user_id': self.get_user_primary_key(request),
            'username': self.get_username(request),
            'ip': self.get_request_ip_address(request),
        }
        for header_name, context_key in META_KEY_TO_CONTEXT_KEY.iteritems():
            # HTTP headers may contain Latin1 characters. Decoding using Latin1 encoding here
            # avoids encountering UnicodeDecodeError exceptions when these header strings are
            # output to tracking logs.
            context[context_key] = request.META.get(header_name,
                                                    '').decode('latin1')

        # Google Analytics uses the clientId to keep track of unique visitors. A GA cookie looks like
        # this: _ga=GA1.2.1033501218.1368477899. The clientId is this part: 1033501218.1368477899.
        google_analytics_cookie = request.COOKIES.get('_ga')
        if google_analytics_cookie is None:
            context['client_id'] = request.META.get('HTTP_X_EDX_GA_CLIENT_ID')
        else:
            context['client_id'] = '.'.join(
                google_analytics_cookie.split('.')[2:])

        context.update(
            contexts.course_context_from_url(request.build_absolute_uri()))

        tracker.get_tracker().enter_context(CONTEXT_NAME, context)
Example #33
0
 def log_event_to_tracking_log(self, block, event_type, event_data):
     """
     Log this XBlock event to the tracking log
     """
     log_context = track.contexts.context_dict_for_learning_context(block.scope_ids.usage_id.context_key)
     if self.user_id:
         log_context['user_id'] = self.user_id
     log_context['asides'] = {}
     track_function = make_track_function()
     with tracker.get_tracker().context(event_type, log_context):
         track_function(event_type, event_data)
Example #34
0
def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix):
    """
    Invoke an XBlock handler, either authenticated or not.

    Arguments:
        request (HttpRequest): the current request
        course_id (str): A string of the form org/course/run
        usage_id (str): A string of the form i4x://org/course/category/name@revision
        handler (str): The name of the handler to invoke
        suffix (str): The suffix to pass to the handler when invoked
    """

    # Check submitted files
    files = request.FILES or {}
    error_msg = _check_files_limits(files)
    if error_msg:
        return JsonResponse(object={
            'success': False,
            'msg': error_msg
        },
                            status=413)

    instance, tracking_context = _get_module_by_usage_id(
        request, course_id, usage_id)

    tracking_context_name = 'module_callback_handler'
    req = django_to_webob_request(request)
    try:
        with tracker.get_tracker().context(tracking_context_name,
                                           tracking_context):
            resp = instance.handle(handler, req, suffix)

    except NoSuchHandlerError:
        log.exception("XBlock %s attempted to access missing handler %r",
                      instance, handler)
        raise Http404

    # If we can't find the module, respond with a 404
    except NotFoundError:
        log.exception("Module indicating to user that request doesn't exist")
        raise Http404

    # For XModule-specific errors, we log the error and respond with an error message
    except ProcessingError as err:
        log.warning("Module encountered an error while processing AJAX call",
                    exc_info=True)
        return JsonResponse(object={'success': err.args[0]}, status=200)

    # If any other error occurred, re-raise it to trigger a 500 response
    except Exception:
        log.exception("error executing xblock handler")
        raise

    return webob_to_django_response(resp)
Example #35
0
    def emit_event(self, event_name):
        """
        Emits an event to explicitly track course enrollment and unenrollment.
        """

        try:
            context = contexts.course_context_from_course_id(self.course_id)
            assert (isinstance(self.course_id, CourseKey))
            data = {
                'user_id': self.user.id,
                'course_id': self.course_id.to_deprecated_string(),
                'mode': self.mode,
            }

            with tracker.get_tracker().context(event_name, context):
                tracker.emit(event_name, data)

                if settings.FEATURES.get(
                        'SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY:
                    tracking_context = tracker.get_tracker().resolve_context()
                    analytics.track(
                        self.user_id,
                        event_name, {
                            'category': 'conversion',
                            'label': self.course_id.to_deprecated_string(),
                            'org': self.course_id.org,
                            'course': self.course_id.course,
                            'run': self.course_id.run,
                            'mode': self.mode,
                        },
                        context={
                            'Google Analytics': {
                                'clientId': tracking_context.get('client_id')
                            }
                        })

        except:  # pylint: disable=bare-except
            if event_name and self.course_id:
                log.exception(
                    'Unable to emit event %s for user %s and course %s',
                    event_name, self.user.username, self.course_id)
Example #36
0
def user_track(request):
    """
    Log when POST call to "event" URL is made by a user. Uses request.REQUEST
    to allow for GET calls.

    GET or POST call should provide "event_type", "event", and "page" arguments.
    """
    try:  # TODO: Do the same for many of the optional META parameters
        username = request.user.username
    except:
        username = "******"

    try:
        scookie = request.META['HTTP_COOKIE']  # Get cookies
        scookie = ";".join([
            c.split('=')[1] for c in scookie.split(";") if "sessionid" in c
        ]).strip()  # Extract session ID
    except:
        scookie = ""

    page = request.REQUEST['page']

    with eventtracker.get_tracker().context(
            'edx.course.browser', contexts.course_context_from_url(page)):
        event = {
            "username": username,
            "session": scookie,
            "ip": _get_request_header(request, 'REMOTE_ADDR'),
            "event_source": "browser",
            "event_type": request.REQUEST['event_type'],
            "event": request.REQUEST['event'],
            "agent": _get_request_header(request, 'HTTP_USER_AGENT'),
            "page": page,
            "time": datetime.datetime.now(UTC),
            "host": _get_request_header(request, 'SERVER_NAME'),
            "context": eventtracker.get_tracker().resolve_context(),
        }

    log_event(event)

    return HttpResponse('success')
Example #37
0
def user_track(request):
    """
    Log when POST call to "event" URL is made by a user. Uses request.REQUEST
    to allow for GET calls.

    GET or POST call should provide "event_type", "event", and "page" arguments.
    """
    try:  # TODO: Do the same for many of the optional META parameters
        username = request.user.username
    except:
        username = "******"

    page = _get_request_value(request, 'page')

    with eventtracker.get_tracker().context(
            'edx.course.browser', contexts.course_context_from_url(page)):
        context = eventtracker.get_tracker().resolve_context()
        event = {
            "username": username,
            "session": context.get('session', ''),
            "ip": _get_request_header(request, 'REMOTE_ADDR'),
            "referer": _get_request_header(request, 'HTTP_REFERER'),
            "accept_language": _get_request_header(request,
                                                   'HTTP_ACCEPT_LANGUAGE'),
            "event_source": "browser",
            "event_type": _get_request_value(request, 'event_type'),
            "event": _get_request_value(request, 'event'),
            "agent": _get_request_header(request, 'HTTP_USER_AGENT'),
            "page": page,
            "time": datetime.datetime.utcnow(),
            "host": _get_request_header(request, 'SERVER_NAME'),
            "context": context,
        }

    # Some duplicated fields are passed into event-tracking via the context by track.middleware.
    # Remove them from the event here since they are captured elsewhere.
    shim.remove_shim_context(event)

    log_event(event)

    return HttpResponse('success')
Example #38
0
def _track_user_registration(user, profile, params, third_party_provider):
    """ Track the user's registration. """
    if hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY:
        tracking_context = tracker.get_tracker().resolve_context()
        identity_args = [
            user.id,
            {
                'email':
                user.email,
                'username':
                user.username,
                'name':
                profile.name,
                # Mailchimp requires the age & yearOfBirth to be integers, we send a sane integer default if falsey.
                'age':
                profile.age or -1,
                'yearOfBirth':
                profile.year_of_birth or datetime.datetime.now(UTC).year,
                'education':
                profile.level_of_education_display,
                'address':
                profile.mailing_address,
                'gender':
                profile.gender_display,
                'country':
                text_type(profile.country),
            }
        ]

        if hasattr(settings, 'MAILCHIMP_NEW_USER_LIST_ID'):
            identity_args.append(
                {"MailChimp": {
                    "listId": settings.MAILCHIMP_NEW_USER_LIST_ID
                }})

        analytics.identify(*identity_args)

        analytics.track(
            user.id,
            "edx.bi.user.account.registered", {
                'category':
                'conversion',
                'label':
                params.get('course_id'),
                'provider':
                third_party_provider.name if third_party_provider else None
            },
            context={
                'ip': tracking_context.get('ip'),
                'Google Analytics': {
                    'clientId': tracking_context.get('client_id')
                }
            })
Example #39
0
 def test_request_with_user(self):
     request = self.request_factory.get('/courses/')
     request.user = User(pk=1)
     self.track_middleware.process_request(request)
     self.addCleanup(self.track_middleware.process_response, request, None)
     self.assertEquals(
         tracker.get_tracker().resolve_context(),
         {
             'course_id': '',
             'org_id': '',
             'user_id': 1
         }
     )
Example #40
0
 def publish(block, event_type, event):
     """A function that allows XModules to publish events."""
     if event_type == 'grade' and not is_masquerading_as_specific_student(user, course_id):
         handle_grade_event(block, event_type, event)
     else:
         aside_context = {}
         for aside in block.runtime.get_asides(block):
             if hasattr(aside, 'get_event_context'):
                 aside_event_info = aside.get_event_context(event_type, event)
                 if aside_event_info is not None:
                     aside_context[aside.scope_ids.block_type] = aside_event_info
         with tracker.get_tracker().context('asides', {'asides': aside_context}):
             track_function(event_type, event)
Example #41
0
def create_tracking_context(user):
    """ Assembles attributes from user and request objects to be sent along
    in E-Commerce API calls for tracking purposes. """
    context_tracker = tracker.get_tracker().resolve_context()
    # Updated by Mahendra
    from lms.djangoapps.reg_form.views import userdetails
    ucountry = userdetails(user.id)
    usercountry = ucountry.rcountry
    return {
        'lms_user_id': user.id,
        'lms_ip': context_tracker.get('ip'),
        'lms_client_id': context_tracker.get('client_id'),
        'lms_user_country': usercountry,
    }
Example #42
0
def emit_certificate_event(event_name,
                           user,
                           course_id,
                           course_overview=None,
                           event_data=None):
    """
    Utility function responsible for emitting certificate events.

    We currently track the following events:
    - `edx.certificate.created` - Emit when a course certificate with the `downloadable` status has been awarded to a
                                  learner.
    - `edx.certificate.revoked`- Emit when a course certificate with the `downloadable` status has been taken away from
                                 a learner.
    - `edx.certificate.shared` - Emit when a learner shares their course certificate to social media (LinkedIn,
                                 Facebook, or Twitter).
    - `edx.certificate.evidence_visited` - Emit when a user (other than the learner who owns a certificate) views a
                                           course certificate (e.g., someone views a course certificate shared on a
                                           LinkedIn profile).

    Args:
        event_name (String) - Text describing the action/event that we are tracking. Examples include `revoked`,
                              `created`, etc.
        user (User) - The User object of the learner associated with this event.
        course_id (CourseLocator) - The course-run key associated with this event.
        course_overview (CourseOverview) - Optional. The CourseOverview of the course-run associated with this event.
        event_data (dictionary) - Optional. Dictionary containing any additional data we want to be associated with an
                                  event.
    """
    event_name = '.'.join(['edx', 'certificate', event_name])

    if not course_overview:
        course_overview = get_course_overview_or_none(course_id)

    context = {'org_id': course_overview.org, 'course_id': str(course_id)}

    data = {
        'user_id':
        user.id,
        'course_id':
        str(course_id),
        'certificate_url':
        get_certificate_url(user.id,
                            course_id,
                            uuid=event_data['certificate_id'])
    }
    event_data = event_data or {}
    event_data.update(data)

    with tracker.get_tracker().context(event_name, context):
        tracker.emit(event_name, event_data)
Example #43
0
    def process_request(self, request):
        """
        Add a user's tags to the tracking event context.
        """
        match = COURSE_REGEX.match(request.build_absolute_uri())
        course_id = None
        if match:
            course_id = match.group('course_id')

        context = {}

        if course_id:
            context['course_id'] = course_id

            if request.user.is_authenticated():
                context['course_user_tags'] = dict(
                    UserCourseTag.objects.filter(
                        user=request.user.pk,
                        course_id=course_id).values_list('key', 'value'))
            else:
                context['course_user_tags'] = {}

        tracker.get_tracker().enter_context(self.CONTEXT_NAME, context)
def track(user_id, event_name, properties=None, context=None, traits=None):
    """
    Wrapper for emitting Segment track event, including augmenting context information from middleware.
    """

    if event_name is not None and hasattr(
            settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY:
        properties = properties or {}
        segment_context = dict(context) if context else {}
        tracking_context = tracker.get_tracker().resolve_context()

        if 'ip' not in segment_context and 'ip' in tracking_context:
            segment_context['ip'] = tracking_context.get('ip')

        if ('Google Analytics' not in segment_context or 'clientId' not in segment_context['Google Analytics']) and 'client_id' in tracking_context:  # lint-amnesty, pylint: disable=line-too-long
            segment_context['Google Analytics'] = {
                'clientId': tracking_context.get('client_id')
            }

        if 'userAgent' not in segment_context and 'agent' in tracking_context:
            segment_context['userAgent'] = tracking_context.get('agent')

        path = tracking_context.get('path')
        referer = tracking_context.get('referer')
        page = tracking_context.get('page')

        if path and not page:
            # Try to put together a url from host and path, hardcoding the schema.
            # (Segment doesn't care about the schema for GA, but will extract the host and path from the url.)
            host = tracking_context.get('host')
            if host:
                parts = ("https", host, path, "", "")
                page = urlunsplit(parts)

        if path is not None or referer is not None or page is not None:
            if 'page' not in segment_context:
                segment_context['page'] = {}
            if path is not None and 'path' not in segment_context['page']:
                segment_context['page']['path'] = path
            if referer is not None and 'referrer' not in segment_context[
                    'page']:
                segment_context['page']['referrer'] = referer
            if page is not None and 'url' not in segment_context['page']:
                segment_context['page']['url'] = page

        if traits:
            segment_context['traits'] = traits

        analytics.track(user_id, event_name, properties, segment_context)
Example #45
0
def track_event(user_id, event_name, properties):
    """
    Emit a track event to segment (and forwarded to GA) for some parts of the Enterprise workflows.
    """
    if getattr(settings, 'LMS_SEGMENT_KEY'):
        tracking_context = tracker.get_tracker().resolve_context()
        analytics.track(user_id,
                        event_name,
                        properties,
                        context={
                            'ip': tracking_context.get('ip'),
                            'Google Analytics': {
                                'clientId': tracking_context.get('client_id')
                            }
                        })
Example #46
0
def server_track(request, event_type, event, page=None):
    """
    Log events related to server requests.

    Handle the situation where the request may be NULL, as may happen with management commands.
    """
    if event_type.startswith("/event_logs") and request.user.is_staff:
        return  # don't log

    try:
        username = request.user.username
    except:
        username = "******"

    # define output:
    event = {
        "username":
        username,
        "ip":
        _get_request_ip(request),
        "referer":
        _get_request_header(request, 'HTTP_REFERER'),
        "accept_language":
        _get_request_header(request, 'HTTP_ACCEPT_LANGUAGE'),
        "event_source":
        "server",
        "event_type":
        event_type,
        "event":
        event,
        "agent":
        _get_request_header(request,
                            'HTTP_USER_AGENT').encode().decode('latin1'),
        "page":
        page,
        "time":
        datetime.datetime.utcnow().replace(tzinfo=pytz.utc),
        "host":
        _get_request_header(request, 'SERVER_NAME'),
        "context":
        eventtracker.get_tracker().resolve_context(),
    }

    # Some duplicated fields are passed into event-tracking via the context by track.middleware.
    # Remove them from the event here since they are captured elsewhere.
    shim.remove_shim_context(event)

    log_event(event)
Example #47
0
def course_grade_now_failed(user, course_id):
    """
    Emits an edx.course.grade.now_failed event
    with data from the course and user failed now .
    """
    event_name = COURSE_GRADE_NOW_FAILED_EVENT_TYPE
    context = contexts.course_context_from_course_id(course_id)
    with tracker.get_tracker().context(event_name, context):
        tracker.emit(
            event_name,
            {
                'user_id': str(user.id),
                'course_id': str(course_id),
                'event_transaction_id': str(get_event_transaction_id()),
                'event_transaction_type': str(get_event_transaction_type())
            }
        )
 def publish_event(event_name, result, **kwargs):
     """
     Helper function to publish an event for analytics purposes
     """
     event_data = {
         "location": unicode(location),
         "previous_count": previous_count,
         "result": result,
         "max_count": max_count,
     }
     event_data.update(kwargs)
     context = contexts.course_context_from_course_id(location.course_key)
     if user_id:
         context['user_id'] = user_id
     full_event_name = "edx.librarycontentblock.content.{}".format(event_name)
     with tracker.get_tracker().context(full_event_name, context):
         tracker.emit(full_event_name, event_data)
Example #49
0
    def emit_event(self, event_name):
        """
        Emits an event to explicitly track course enrollment and unenrollment.
        """

        try:
            context = contexts.course_context_from_course_id(self.course_id)
            data = {
                'user_id': self.user.id,
                'course_id': self.course_id,
                'mode': self.mode,
            }

            with tracker.get_tracker().context(event_name, context):
                tracker.emit(event_name, data)
        except:  # pylint: disable=bare-except
            if event_name and self.course_id:
                log.exception('Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id)
Example #50
0
def course_grade_passed_first_time(user_id, course_id):
    """
    Emits an event edx.course.grade.passed.first_time
    with data from the passed course_grade.
    """
    event_name = COURSE_GRADE_PASSED_FIRST_TIME_EVENT_TYPE
    context = contexts.course_context_from_course_id(course_id)
    # TODO (AN-6134): remove this context manager
    with tracker.get_tracker().context(event_name, context):
        tracker.emit(
            event_name,
            {
                'user_id': str(user_id),
                'course_id': str(course_id),
                'event_transaction_id': str(get_event_transaction_id()),
                'event_transaction_type': str(get_event_transaction_type())
            }
        )
Example #51
0
def track(user_id, event_name, properties=None, context=None):
    """Wrapper for emitting Segment track event, including augmenting context information from middleware."""

    if event_name is not None and hasattr(
            settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY:
        properties = properties or {}
        segment_context = dict(context) if context else {}
        tracking_context = tracker.get_tracker().resolve_context()

        if 'ip' not in segment_context and 'ip' in tracking_context:
            segment_context['ip'] = tracking_context.get('ip')

        if ('Google Analytics' not in segment_context
                or 'clientId' not in segment_context['Google Analytics']
            ) and 'client_id' in tracking_context:
            segment_context['Google Analytics'] = {
                'clientId': tracking_context.get('client_id')
            }

        if 'userAgent' not in segment_context and 'agent' in tracking_context:
            segment_context['userAgent'] = tracking_context.get('agent')

        path = tracking_context.get('path')
        referer = tracking_context.get('referer')
        page = tracking_context.get('page')

        if path and not page:
            # Try to put together a url from host and path:
            host = tracking_context.get('host')
            if host:
                page = urljoin("//{host}".format(host=host), path)

        if path is not None or referer is not None or page is not None:
            if 'page' not in segment_context:
                segment_context['page'] = {}
            if path is not None and 'path' not in segment_context['page']:
                segment_context['page']['path'] = path
            if referer is not None and 'referrer' not in segment_context[
                    'page']:
                segment_context['page']['referrer'] = referer
            if page is not None and 'url' not in segment_context['page']:
                segment_context['page']['url'] = page

        analytics.track(user_id, event_name, properties, segment_context)
Example #52
0
def user_track(request):
    """
    Log when POST call to "event" URL is made by a user.

    GET or POST call should provide "event_type", "event", and "page" arguments.
    """
    try:
        username = request.user.username
    except:
        username = "******"

    name = _get_request_value(request, 'event_type')
    data = _get_request_value(request, 'event', {})
    page = _get_request_value(request, 'page')

    if isinstance(data, six.string_types) and len(data) > 0:
        try:
            data = json.loads(data)
            _add_user_id_for_username(data)
        except ValueError:
            pass

    context_override = contexts.course_context_from_url(page)
    context_override['username'] = username
    context_override['event_source'] = 'browser'
    context_override['page'] = page

    if settings.LRS_ENDPOINT:
        lrs_data = {
            'activity_time': timezone.now().isoformat(),
            'actor': request.user.id,
            'verb': name,
            'activity_object': page,
            'extra_data': json.dumps(data, default=str),
        }
        attempt_to_store_lrs_record.apply_async(args=[lrs_data],
                                                queue=settings.LRS_QUEUE)

    with eventtracker.get_tracker().context('edx.course.browser',
                                            context_override):
        eventtracker.emit(name=name, data=data)

    return HttpResponse('success')
Example #53
0
 def publish(block, event_type, event):
     """
     A function that allows XModules to publish events.
     """
     handle_event = get_event_handler(event_type)
     if handle_event and not is_masquerading_as_specific_student(user, course_id):
         handle_event(block, event)
     else:
         context = contexts.course_context_from_course_id(course_id)
         if block.runtime.user_id:
             context['user_id'] = block.runtime.user_id
         context['asides'] = {}
         for aside in block.runtime.get_asides(block):
             if hasattr(aside, 'get_event_context'):
                 aside_event_info = aside.get_event_context(event_type, event)
                 if aside_event_info is not None:
                     context['asides'][aside.scope_ids.block_type] = aside_event_info
         with tracker.get_tracker().context(event_type, context):
             track_function(event_type, event)
 def publish(block, event_type, event):
     """A function that allows XModules to publish events."""
     if event_type == 'grade':
         handle_grade_event(block, event_type, event)
     elif event_type == 'progress':
         # expose another special case event type which gets sent
         # into the CourseCompletions models
         handle_progress_event(block, event_type, event)
     else:
         context = contexts.course_context_from_course_id(course_id)
         if block.runtime.user_id:
             context['user_id'] = block.runtime.user_id
         context['asides'] = {}
         for aside in block.runtime.get_asides(block):
             if hasattr(aside, 'get_event_context'):
                 aside_event_info = aside.get_event_context(event_type, event)
                 if aside_event_info is not None:
                     context['asides'][aside.scope_ids.block_type] = aside_event_info
         with tracker.get_tracker().context(event_type, context):
             track_function(event_type, event)
Example #55
0
    def _fire_event(self, user, event_name, parameters):
        """
        Fire an analytics event.

        Arguments:
            user (User): The user who submitted photos.
            event_name (str): Name of the analytics event.
            parameters (dict): Event parameters.

        Returns: None

        """
        if settings.LMS_SEGMENT_KEY:
            tracking_context = tracker.get_tracker().resolve_context()
            context = {
                'ip': tracking_context.get('ip'),
                'Google Analytics': {
                    'clientId': tracking_context.get('client_id')
                }
            }
            analytics.track(user.id, event_name, parameters, context=context)
Example #56
0
def emit_certificate_event(event_name, user, course_id, course=None, event_data=None):
    """
    Emits certificate event.
    """
    event_name = '.'.join(['edx', 'certificate', event_name])
    if course is None:
        course = modulestore().get_course(course_id, depth=0)
    context = {
        'org_id': course.org,
        'course_id': unicode(course_id)
    }
    data = {
        'user_id': user.id,
        'course_id': unicode(course_id),
        'certificate_url': get_certificate_url(user.id, course_id)
    }
    event_data = event_data or {}
    event_data.update(data)

    with tracker.get_tracker().context(event_name, context):
        tracker.emit(event_name, event_data)
Example #57
0
def login_analytics(strategy, auth_entry, *args, **kwargs):
    """ Sends login info to Segment.io """

    event_name = None
    if auth_entry in [AUTH_ENTRY_LOGIN, AUTH_ENTRY_LOGIN_2]:
        event_name = 'edx.bi.user.account.authenticated'
    elif auth_entry in [AUTH_ENTRY_ACCOUNT_SETTINGS]:
        event_name = 'edx.bi.user.account.linked'

    if event_name is not None:
        tracking_context = tracker.get_tracker().resolve_context()
        analytics.track(kwargs['user'].id,
                        event_name, {
                            'category': "conversion",
                            'label': None,
                            'provider': getattr(kwargs['backend'], 'name')
                        },
                        context={
                            'Google Analytics': {
                                'clientId': tracking_context.get('client_id')
                            }
                        })
Example #58
0
def subsection_grade_calculated(subsection_grade):
    """
    Emits an edx.grades.subsection.grade_calculated event
    with data from the passed subsection_grade.
    """
    event_name = SUBSECTION_GRADE_CALCULATED
    context = contexts.course_context_from_course_id(
        subsection_grade.course_id)
    # TODO (AN-6134): remove this context manager
    with tracker.get_tracker().context(event_name, context):
        tracker.emit(
            event_name, {
                'user_id':
                unicode(subsection_grade.user_id),
                'course_id':
                unicode(subsection_grade.course_id),
                'block_id':
                unicode(subsection_grade.usage_key),
                'course_version':
                unicode(subsection_grade.course_version),
                'weighted_total_earned':
                subsection_grade.earned_all,
                'weighted_total_possible':
                subsection_grade.possible_all,
                'weighted_graded_earned':
                subsection_grade.earned_graded,
                'weighted_graded_possible':
                subsection_grade.possible_graded,
                'first_attempted':
                unicode(subsection_grade.first_attempted),
                'subtree_edited_timestamp':
                unicode(subsection_grade.subtree_edited_timestamp),
                'event_transaction_id':
                unicode(get_event_transaction_id()),
                'event_transaction_type':
                unicode(get_event_transaction_type()),
                'visible_blocks_hash':
                unicode(subsection_grade.visible_blocks_id),
            })
Example #59
0
def login_analytics(strategy, *args, **kwargs):
    """ Sends login info to Segment.io """
    event_name = None

    action_to_event_name = {
        'is_login': '******',
        'is_dashboard': 'edx.bi.user.account.linked',
        'is_profile': 'edx.bi.user.account.linked',

        # Backwards compatibility: during an A/B test for the combined
        # login/registration form, we introduced a new login end-point.
        # Since users may continue to have this in their sessions after
        # the test concludes, we need to continue accepting this action.
        'is_login_2': 'edx.bi.user.account.authenticated',
    }

    # Note: we assume only one of the `action` kwargs (is_dashboard, is_login) to be
    # `True` at any given time
    for action in action_to_event_name.keys():
        if kwargs.get(action):
            event_name = action_to_event_name[action]

    if event_name is not None:
        tracking_context = tracker.get_tracker().resolve_context()
        analytics.track(
            kwargs['user'].id,
            event_name,
            {
                'category': "conversion",
                'label': strategy.session_get('enroll_course_id'),
                'provider': getattr(kwargs['backend'], 'name')
            },
            context={
                'Google Analytics': {
                    'clientId': tracking_context.get('client_id')
                }
            }
        )
Example #60
0
 def _emit_grade_calculated_event(grade):
     """
     Emits an edx.grades.subsection.grade_calculated event
     with data from the passed grade.
     """
     # TODO: remove this context manager after completion of AN-6134
     event_name = u'edx.grades.subsection.grade_calculated'
     context = contexts.course_context_from_course_id(grade.course_id)
     with tracker.get_tracker().context(event_name, context):
         tracker.emit(
             event_name, {
                 'user_id':
                 unicode(grade.user_id),
                 'course_id':
                 unicode(grade.course_id),
                 'block_id':
                 unicode(grade.usage_key),
                 'course_version':
                 unicode(grade.course_version),
                 'weighted_total_earned':
                 grade.earned_all,
                 'weighted_total_possible':
                 grade.possible_all,
                 'weighted_graded_earned':
                 grade.earned_graded,
                 'weighted_graded_possible':
                 grade.possible_graded,
                 'first_attempted':
                 unicode(grade.first_attempted),
                 'subtree_edited_timestamp':
                 unicode(grade.subtree_edited_timestamp),
                 'event_transaction_id':
                 unicode(get_event_transaction_id()),
                 'event_transaction_type':
                 unicode(get_event_transaction_type()),
                 'visible_blocks_hash':
                 unicode(grade.visible_blocks_id),
             })