B
    h1                 @   s`   d dl Z d dlZd dlZd dlZd dlZd dlmZ ejej	d e
eZG dd deZdS )    N)params_dict)levelc               @   st   e Zd ZdZdd ZdddZdd	 Zd
d ZdddZdd Z	dd Z
dd Zdd Zdd Zdd Zdd ZdS )Ga4mpaj  
    Class that provides an interface for sending data to Google Analytics, supporting the GA4 Measurement Protocol.

    Parameters
    ----------
    measurement_id : string
        The identifier for a Data Stream. Found in the Google Analytics UI under: Admin > Data Streams > choose your stream > Measurement ID
    api_secret : string
        Generated throught the Google Analytics UI. To create a new secret, navigate in the Google Analytics UI to: Admin > Data Streams >
        choose your stream > Measurement Protocol > Create
    client_id : string
        Getting your Google API client ID: https://developers.google.com/identity/one-tap/web/guides/get-google-api-clientid


    See Also
    --------

    * Measurement Protocol (Google Analytics 4): https://developers.google.com/analytics/devguides/collection/protocol/ga4

    Examples
    --------

    >>> ga = Ga4mp(measurement_id = "MEASUREMENT_ID", api_secret = "API_SECRET", client_id="CLIENT_ID")
    >>> event_type = 'new_custom_event'
    >>> event_parameters = {'paramater_key_1': 'parameter_1', 'paramater_key_2': 'parameter_2'}
    >>> event = {'name': event_type, 'params': event_parameters }
    >>> events = [event]

    # Send a custom event to GA4 immediately
    >>> ga.send(events)

    # Postponed send of a custom event to GA4
    >>> ga.send(events, postpone=True)
    >>> ga.postponed_send()
    c             C   s.   || _ || _|| _g | _i | _d| _d| _d S )Nz+https://www.google-analytics.com/mp/collectz1https://www.google-analytics.com/debug/mp/collect)measurement_id
api_secret	client_id_event_list_user_properties_base_domain_validation_domain)selfr   r   r    r   HC:\Users\sanjo\AppData\Local\Qlobot\Launcher\ext_packages\ga4mp\ga4mp.py__init__:   s    zGa4mp.__init__FNc                s|   |    | | |dkrJxZ D ]"}| t |d< | j| q"W n. fddtdt dD }| j|||d dS )	a  
        Method to send an http post request to google analytics with the specified events.

        Parameters
        ----------
        events : List[Dict]
            A list of dictionaries  of the events to be sent to Google Analytics. The list of dictionaries should adhere
            to the following format:

            [{'name': 'level_end',
            'params' : {'level_name': 'First',
                        'success': 'True'}
            },
            {'name': 'level_up',
            'params': {'character': 'John Madden',
                        'level': 'First'}
            }]

        validation_hit : bool, optional
            Boolean to depict if events should be tested against the Measurement Protocol Validation Server, by default False
        postpone : bool, optional
            Boolean to depict if provided event list should be postponed, by default False
        date : datetime
            Python datetime object for sending a historical event at the given date. Date cannot be in the future.
        T_timestamp_microsc                s   g | ]} ||d   qS )   r   ).0event)eventsr   r   
<listcomp>j   s    zGa4mp.send.<locals>.<listcomp>r   r   )validation_hitdateN)	_check_params_check_date_not_in_future_get_timestamptimer   appendrangelen
_http_post)r   r   r   postponer   r   batched_event_listr   )r   r   sendC   s    


z
Ga4mp.sendc             C   s*   x| j D ]}| j|gdd qW g | _ dS )zX
        Method to send the events provided to Ga4mp.send(events,postpone=True)
        T)r    N)r   r   )r   r   r   r   r   postponed_sendq   s    zGa4mp.postponed_sendc             C   s   t | dS )a  
        Method to append event name and parameters key-value pair to parameters dictionary.

        Parameters
        ----------
        new_name_and_parameters : Dict
            A dictionary with one key-value pair representing a new type of event to be sent to Google Analytics.
            The dictionary should adhere to the following format:

            {'new_name': ['new_param_1', 'new_param_2', 'new_param_3']}
        N)r   update)r   Znew_name_and_parametersr   r   r   append_event_to_params_dict|   s    z!Ga4mp.append_event_to_params_dictc             C   s|  |  | d}| j}|dkr"| j}td|  d}x>|D ]4}| d| j d| j }	| j|d}
| |
 |r|d |d	 d
n||
d< |dk	rtd|  |dkst	d| 
|}| |}t||
d< td|
d   |r|d |
d< tj|	}|dd t|
}|d}|dt| tj||}|j}td|  td|  |d7 }q>W |S )aR  
        Method to send http POST request to google-analytics.

        Parameters
        ----------
        batched_event_list : List[List[Dict]]
            List of List of events. Places initial event payload into a list to send http POST in batches.
        validation_hit : bool, optional
            Boolean to depict if events should be tested against the Measurement Protocol Validation Server, by default False
        postpone : bool, optional
            Boolean to depict if provided event list should be postponed, by default False
        date : datetime
            Python datetime object for sending a historical event at the given date. Date cannot be in the future.
            Timestamp micros supports up to 48 hours of backdating.
            If date is specified, postpone must be False or an assertion will be thrown.
        NTzSending POST to:    z?measurement_id=z&api_secret=)r   r   nameparams)r'   r(   r   zSetting event timestamp to: Fz;Cannot send postponed historical hit, ensure postpone=FalseZtimestamp_microszTimestamp of request is: r   zContent-Typezapplication/json; charset=utf-8zutf-8zContent-LengthzBatch Number: zStatus code: )r   r
   r   loggerinfor   r   r   _add_user_props_to_hitAssertionError_datetime_to_timestampr   inturllibrequestRequest
add_headerjsondumpsencoder   urlopenstatus)r   r!   r   r    r   status_codedomainZbatch_numberbatchurlr0   tsZts_microreqZjsondataZjson_data_as_bytesresultr   r   r   r      sD    






zGa4mp._http_postc          	   C   s   t |tkstdx@|D ]8}t |tks2tdd|ksBtdd|kstdqW xb|D ]Z}|d }|d }|t kr\x8t| D ],}|| krtd| dt|  d	 qW q\W d
S )af  
        Method to check whether the event payload parameters provided meets supported parameters.

        Parameters
        ----------
        events : List[Dict]
            A list of dictionaries  of the events to be sent to Google Analytics. The list of dictionaries should adhere
            to the following format:

            [{'name': 'level_end',
            'params' : {'level_name': 'First',
                        'success': 'True'}
            },
            {'name': 'level_up',
            'params': {'character': 'John Madden',
                        'level': 'First'}
            }]
        zevents should be a listz!each event should be a dictionaryr'   z#each event should have a "name" keyr(   z%each event should have a "params" keyz7WARNING: Event parameters do not match event type.
For z* event type, the correct parameter(s) are z.
For a breakdown of currently supported event types and their parameters go here: https://support.google.com/analytics/answer/9267735
N)typelistr,   dictr   keysr)   warning)r   r   r   eZ
event_nameZevent_paramsZ	parameterr   r   r   r      s    

zGa4mp._check_paramsc             C   s   | j ||i dS )z
        Method to set user_id, user_properties, non_personalized_ads

        Parameters
        ----------
        property : string
        value: dependent on property (user_id, user_properties - string, non_personalized_ads - bool)
        N)r	   r$   )r   propertyvaluer   r   r   set_user_property   s    
zGa4mp.set_user_propertyc             C   s@   y|| j  kr| j | W n   td|  Y nX dS )z
        Method to remove user_id, user_properties, non_personalized_ads

        Parameters
        ----------
        property : string
        z Failed to delete user property: N)r	   rB   popr)   r*   )r   rE   r   r   r   delete_user_property  s
    	zGa4mp.delete_user_propertyc             C   s   x| j D ]z}yX|dkr,||| j | i n6d| krF|di i |d |d| j | ii W q   td|  Y qX qW dS )z
        Method is a helper function to add user properties to outgoing hits.

        Parameters
        ----------
        hit : dict
        )Zuser_idZnon_personalized_adsZuser_propertiesrF   z-Failed to add user property to outgoing hit: N)r	   r$   rB   r)   r*   )r   hitkeyr   r   r   r+     s    	zGa4mp._add_user_props_to_hitc             C   s   t |d S )z
        Method returns UNIX timestamp in microseconds for postponed hits.

        Parameters
        ----------
        None
        g    .A)r.   )r   	timestampr   r   r   r   1  s    zGa4mp._get_timestampc             C   s   t | S )a  
        Private method to convert a datetime object into a timestamp

        Parameters
        ----------
        dt : datetime
            A datetime object in any format

        Returns
        -------
        timestamp
            A UNIX timestamp in milliseconds
        )r   mktime	timetuple)r   dtr   r   r   r-   ;  s    zGa4mp._datetime_to_timestampc             C   s$   |dkr
n|t j  ks tddS )z
        Method to check that provided date is not in the future.

        Parameters
        ----------
        date : datetime
            Python datetime object
        Nz%Provided date cannot be in the future)datetimenowr,   )r   r   r   r   r   r   K  s    	zGa4mp._check_date_not_in_future)FFN)FFN)__name__
__module____qualname____doc__r   r"   r#   r%   r   r   rG   rI   r+   r   r-   r   r   r   r   r   r      s   #	
.
F-
r   )r3   loggingurllib.requestr/   r   rP   Zga4mp.utilsr   basicConfigINFO	getLoggerrR   r)   objectr   r   r   r   r   <module>
   s   
