<commit_before>"""
Custom event processors and other functionality for the Segment backend.
"""

from django.conf import settings

from openedx.core.djangoapps.site_configuration import helpers

from . import exceptions, utils


class SegmentTopLevelPropertiesProcessor(object):
    """

    Most Segment.io Destination APIs require properties to be at the top level
    of the event. Copy all properties contained within the event's 'data' key
    to the top level of the event dict.

    We copy properties instead of reassign to not break previous integrations.

    For example: by default, tracker.emit() will produce an event
    with most interesting properties in the `data` key, like:

    analytics.track('13', 'edx.bi.completion.user.chapter.started', {
    'context': { ... },
    'data': {
        'block_id': 'block-v1:foo+101+forever+type@chapter+block@3707382f0c284b6aadbd7c50d767ca8f',
        'block_name': 'Section 1',
        'completion_percent': 33.3333333333333,
        'course_id': 'course-v1:foo+101+forever',
        'course_name': 'CompletionTest',
        'label': 'chapter Section 1 started'
    },
    'name': 'edx.bi.completion.user.chapter.started',
    ...
    })

    Many/most Segment Destinations will not be able to access properties inside 'data'.
    Copy these to the top level of the event before emitting.
    For example, the previous becomes:
    analytics.track('13', 'edx.bi.completion.user.chapter.started', {
    'context': { ... },
    'block_id': 'block-v1:foo+101+forever+type@chapter+block@3707382f0c284b6aadbd7c50d767ca8f',
    'block_name': 'Section 1',
    'completion_percent': 33.3333333333333,
    'course_id': 'course-v1:foo+101+forever',
    'course_name': 'CompletionTest',
    'label': 'chapter Section 1 started',
    'data': {
        'block_id': 'block-v1:foo+101+forever+type@chapter+block@3707382f0c284b6aadbd7c50d767ca8f',
        'block_name': 'Section 1',
        'completion_percent': 33.3333333333333,
        'course_id': 'course-v1:foo+101+forever',
        'course_name': 'CompletionTest',
        'label': 'chapter Section 1 started'
    },
    'name': 'edx.bi.completion.user.chapter.started',
    ...
    })


    Always returns the event for continued processing.
    """

    def __call__(self, event):
        """
        Process only if processor is enabled for Site.
        """
        try:
            siteconfig = utils.get_site_config_for_event(event['data'])
            if not siteconfig.get_value(
                'COPY_SEGMENT_EVENT_PROPERTIES_TO_TOP_LEVEL',
                settings.COPY_SEGMENT_EVENT_PROPERTIES_TO_TOP_LEVEL
            ):
                return event
        except exceptions.EventProcessingError:
            return event

        try:
            for key, val in event['data'].items():
                if key in event:
                    try:
                        event[key].update(event['data'][key])  # dict
                    except AttributeError:
                        try:
                            event[key].extend(event['data'][key])  # list
                        except AttributeError:
                            event[key] = val
                else:
                    event[key] = val
        except KeyError:  # no 'data'
            pass
        return event<commit_msg>Segment top level properties processor don't assume SiteConfig was found for event<commit_after>"""
Custom event processors and other functionality for the Segment backend.
"""

from django.conf import settings

from openedx.core.djangoapps.site_configuration import helpers

from . import exceptions, utils


class SegmentTopLevelPropertiesProcessor(object):
    """

    Most Segment.io Destination APIs require properties to be at the top level
    of the event. Copy all properties contained within the event's 'data' key
    to the top level of the event dict.

    We copy properties instead of reassign to not break previous integrations.

    For example: by default, tracker.emit() will produce an event
    with most interesting properties in the `data` key, like:

    analytics.track('13', 'edx.bi.completion.user.chapter.started', {
    'context': { ... },
    'data': {
        'block_id': 'block-v1:foo+101+forever+type@chapter+block@3707382f0c284b6aadbd7c50d767ca8f',
        'block_name': 'Section 1',
        'completion_percent': 33.3333333333333,
        'course_id': 'course-v1:foo+101+forever',
        'course_name': 'CompletionTest',
        'label': 'chapter Section 1 started'
    },
    'name': 'edx.bi.completion.user.chapter.started',
    ...
    })

    Many/most Segment Destinations will not be able to access properties inside 'data'.
    Copy these to the top level of the event before emitting.
    For example, the previous becomes:
    analytics.track('13', 'edx.bi.completion.user.chapter.started', {
    'context': { ... },
    'block_id': 'block-v1:foo+101+forever+type@chapter+block@3707382f0c284b6aadbd7c50d767ca8f',
    'block_name': 'Section 1',
    'completion_percent': 33.3333333333333,
    'course_id': 'course-v1:foo+101+forever',
    'course_name': 'CompletionTest',
    'label': 'chapter Section 1 started',
    'data': {
        'block_id': 'block-v1:foo+101+forever+type@chapter+block@3707382f0c284b6aadbd7c50d767ca8f',
        'block_name': 'Section 1',
        'completion_percent': 33.3333333333333,
        'course_id': 'course-v1:foo+101+forever',
        'course_name': 'CompletionTest',
        'label': 'chapter Section 1 started'
    },
    'name': 'edx.bi.completion.user.chapter.started',
    ...
    })


    Always returns the event for continued processing.
    """

    def __call__(self, event):
        """
        Process only if processor is enabled for Site.
        """
        try:
            siteconfig = utils.get_site_config_for_event(event['data'])
            if not siteconfig.get_value(
                'COPY_SEGMENT_EVENT_PROPERTIES_TO_TOP_LEVEL',
                settings.COPY_SEGMENT_EVENT_PROPERTIES_TO_TOP_LEVEL
            ):
                return event
        except (AttributeError, exceptions.EventProcessingError):
            return event

        try:
            for key, val in event['data'].items():
                if key in event:
                    try:
                        event[key].update(event['data'][key])  # dict
                    except AttributeError:
                        try:
                            event[key].extend(event['data'][key])  # list
                        except AttributeError:
                            event[key] = val
                else:
                    event[key] = val
        except KeyError:  # no 'data'
            pass
        return event
{'fraction_non_alphanumeric': 0.10725458066438254, 'fraction_numerical': 0.04051839713987785, 'mean_word_length': 2.399493670886076, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 6, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1460563', 'n_tokens_mistral': 2153, 'n_tokens_neox': 1905, 'n_words': 487}