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.matomo;
017
018import java.net.URI;
019import java.util.HashMap;
020import java.util.Map;
021import java.util.Random;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.commons.lang3.StringUtils;
026import org.matomo.java.tracking.MatomoTracker;
027import org.matomo.java.tracking.TrackerConfiguration;
028
029import org.ametys.core.util.URIUtils;
030import org.ametys.plugins.webanalytics.matomo.tracking.MatomoTrackingProvider;
031import org.ametys.plugins.webanalytics.matomo.tracking.MatomoTrackingProviderExtensionPoint;
032import org.ametys.runtime.config.Config;
033import org.ametys.runtime.plugin.component.DeferredServiceable;
034import org.ametys.web.analytics.AbstractWebAnalyticsProvider;
035import org.ametys.web.repository.site.Site;
036
037/**
038 * The matomo analytics provider
039 */
040public class MatomoAnalyticsProvider extends AbstractWebAnalyticsProvider implements DeferredServiceable 
041{
042    private static final Random _RNG = new Random((long) Math.random() * System.nanoTime());
043    
044    /** The Matomo tracking extension point */
045    protected MatomoTrackingProviderExtensionPoint _matomoTrackingEP;
046    
047    public void deferredService(ServiceManager manager) throws ServiceException
048    {
049        if (manager.hasService(MatomoTrackingProviderExtensionPoint.ROLE))
050        {
051            _matomoTrackingEP = (MatomoTrackingProviderExtensionPoint) manager.lookup(MatomoTrackingProviderExtensionPoint.ROLE);
052        }
053    }
054    
055    public String getEventImageUri(Site site, String category, String action, String label, int value, boolean usePlaceholderTokens)
056    {
057        _checkSafeMode();
058
059        String matomoUrl = Config.getInstance().getValue(MatomoDataHelper.MATOMO_URL_CONFIG);
060        String siteId = site.getValue(MatomoDataHelper.MATOMO_SITE_ID_SITE_CONFIG);
061        if (StringUtils.isNotBlank(matomoUrl) && StringUtils.isNotBlank(siteId))
062        {
063            Map<String, String> uriParameters = new HashMap<>();
064            uriParameters.put("idsite", siteId);
065            uriParameters.put("rec", "1");
066            uriParameters.put("bots", "1");
067            uriParameters.put("ca", "1");
068            uriParameters.put("e_c", category);
069            uriParameters.put("e_a", action);
070            uriParameters.put("e_n", label);
071            if (value > 0)
072            {
073                uriParameters.put("e_v", String.valueOf(value));
074            }
075            uriParameters.put("rand", usePlaceholderTokens ? RANDOM_NUMBER_TOKEN : String.valueOf(_RNG.nextInt(Integer.MAX_VALUE)));
076            
077            return URIUtils.encodeURI(matomoUrl + "/matomo.php", uriParameters);
078        }
079        
080        return null;
081    }
082    
083    public String getEventLinkCampaignParams(Site site, String campaign, String medium, String source)
084    {
085        _checkSafeMode();
086
087        StringBuilder linkCampaignParams = new StringBuilder();
088        linkCampaignParams.append("mtm_campaign=");
089        linkCampaignParams.append(campaign);
090        linkCampaignParams.append("&mtm_medium=");
091        linkCampaignParams.append(medium);
092        linkCampaignParams.append("&mtm_source=");
093        linkCampaignParams.append(source);
094        
095        return linkCampaignParams.toString();
096    }
097    
098    public void sendTrackingInformation(Site site) throws Exception
099    {
100        _checkSafeMode();
101        
102        String matomoUrl = Config.getInstance().getValue(MatomoDataHelper.MATOMO_URL_CONFIG);
103        if (StringUtils.isNotBlank(matomoUrl))
104        {
105            String siteId = site.getValue(MatomoDataHelper.MATOMO_SITE_ID_SITE_CONFIG);
106            if (StringUtils.isNotBlank(siteId))
107            {
108                try
109                {
110                    TrackerConfiguration configuration = TrackerConfiguration.builder()
111                            .apiEndpoint(URI.create(matomoUrl + "/matomo.php"))
112                            .defaultSiteId(Integer.valueOf(siteId))
113                            .build();
114                    try (MatomoTracker tracker = new MatomoTracker(configuration))
115                    {
116                        for (String id : _matomoTrackingEP.getExtensionsIds())
117                        {
118                            MatomoTrackingProvider trackingProvider = _matomoTrackingEP.getExtension(id);
119                            tracker.sendBulkRequestAsync(trackingProvider.getRequests(site));
120                        }
121                    }
122                }
123                catch (Exception e) 
124                {
125                    getLogger().error("An error occurred tracking site {} ({}) to Matomo", site.getName(), siteId, e);            
126                }
127            }
128        }
129    }
130    
131    private void _checkSafeMode()
132    {
133        if (_matomoTrackingEP == null)
134        {
135            throw new IllegalStateException("MatomoTrackingProviderExtensionPoint service is not available in safe mode.");
136        }
137    }
138}