001/*
002 *  Copyright 2023 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.webanalytics.ga;
017
018import java.net.URISyntaxException;
019import java.util.Random;
020
021import org.apache.commons.lang.StringUtils;
022
023import org.ametys.core.util.URIUtils;
024import org.ametys.web.analytics.AbstractWebAnalyticsProvider;
025import org.ametys.web.repository.site.Site;
026
027/**
028 * The google analytics provider
029 */
030public class GoogleAnalyticsProvider extends AbstractWebAnalyticsProvider
031{
032    /** The analytics GIF URL. */
033    public static final String GA_GIF_URL = "https://www.google-analytics.com/__utm.gif";
034    
035    /** The analytics API version. */
036    public static final String GA_VERSION = "5.3.8";
037    
038    /** The domain hash. */
039    public static final String DOMAIN_HASH = "109627128"; // TODO Really hash the domain name?
040    
041    private static final Random _RNG = new Random((long) Math.random() * System.nanoTime());
042    
043    public String getEventImageUri(Site site, String category, String action, String label, int value, boolean usePlaceholderTokens)
044    {
045        String gaWebId = site.getValue("google-web-property-id");
046        if (StringUtils.isNotBlank(gaWebId))
047        {
048            String identifier = _getEventIdentifier(category, action, label, value);
049            return _getEventImageUri(gaWebId, identifier, usePlaceholderTokens);
050        }
051        
052        return null;
053    }
054    
055    /**
056     * Get the event identifier
057     * @param category the event category
058     * @param action the event action
059     * @param label the event label
060     * @param value the event value
061     * @return the event identifier
062     */
063    protected String _getEventIdentifier(String category, String action, String label, int value)
064    {
065        try
066        {
067            StringBuilder eventId = new StringBuilder();
068            
069            eventId.append("5(");
070            eventId.append(_encodeValue(category));
071            eventId.append('*').append(_encodeValue(action));
072            eventId.append('*').append(_encodeValue(label));
073            eventId.append(')');
074            if (value > 0)
075            {
076                eventId.append('(').append(value).append(')');
077            }
078            return eventId.toString();
079        }
080        catch (URISyntaxException e)
081        {
082            getLogger().error("An error occurred computing the event gif uri", e);
083        }
084        
085        return null;
086    }
087    
088    /**
089     * Get an event image URI.
090     * @param gaWebId the GA web ID.
091     * @param eventIdentifier the event identifier.
092     * @param usePlaceholderTokens True to use tokens instead of randomly generated values
093     * @return the event image URI.
094     */
095    protected String _getEventImageUri(String gaWebId, String eventIdentifier, boolean usePlaceholderTokens)
096    {
097        long now = System.currentTimeMillis() / 1000L;
098        
099        StringBuilder cookieValue = new StringBuilder();
100        // UTMA
101        cookieValue.append("__utma=").append(DOMAIN_HASH).append('.').append(usePlaceholderTokens ? RANDOM_NUMBER_TOKEN : _RNG.nextInt(Integer.MAX_VALUE));
102        cookieValue.append('.').append(now).append('.').append(now).append('.').append(now).append(".1");
103        // UTMZ
104        cookieValue.append(";+__utmz=").append(DOMAIN_HASH).append('.').append(now);
105        cookieValue.append(".1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);");
106        
107        StringBuilder uri = new StringBuilder();
108        
109        uri.append(GA_GIF_URL);
110        uri.append("?utmwv=").append(GA_VERSION);
111        uri.append("&utmn=").append(usePlaceholderTokens ? RANDOM_NUMBER_TOKEN : _RNG.nextInt(Integer.MAX_VALUE));
112        uri.append("&utmt=event");
113        uri.append("&utme=").append(eventIdentifier);
114        uri.append("&utmcs=UTF-8");
115        uri.append("&utmje=1");
116        uri.append("&utmhid=").append(usePlaceholderTokens ? RANDOM_NUMBER_TOKEN : _RNG.nextInt(Integer.MAX_VALUE));
117        // TODO utmhn with main domain?
118        uri.append("&utmr=-");
119        uri.append("&utmac=").append(gaWebId);
120        
121        // Cookie
122        String encodedCookie = URIUtils.encodeParameter(cookieValue.toString());
123        uri.append("&utmcc=").append(encodedCookie);
124        
125        return uri.toString();
126    }
127    
128    public String getEventLinkCampaignParams(Site site, String campaign, String medium, String source)
129    {
130        StringBuilder linkCampaignParams = new StringBuilder();
131        linkCampaignParams.append("utm_campaign=");
132        linkCampaignParams.append(campaign);
133        linkCampaignParams.append("&utm_medium=");
134        linkCampaignParams.append(medium);
135        linkCampaignParams.append("&utm_source=");
136        linkCampaignParams.append(source);
137        
138        return linkCampaignParams.toString();
139    }
140}