diff options
author | benakamoorthi <benaka.moorthi@gmail.com> | 2012-11-24 12:01:10 +0400 |
---|---|---|
committer | benakamoorthi <benaka.moorthi@gmail.com> | 2012-11-24 12:01:10 +0400 |
commit | 4f4959338dd5d0b5acb8747d21b865d5a06e89a6 (patch) | |
tree | 1d5630ce62c2330522829f82abf3ec40498a9903 | |
parent | 842ece5d0052864b9c70cce3c318bd9918b985e5 (diff) |
Fixes #2375, added ability to exclude visits from tracking based on global & site-specific blacklists user agent substrings. Also fixed bug in website management page that broke website editing/creation.
git-svn-id: http://dev.piwik.org/svn/trunk@7535 59fd770c-687e-43c8-a1e3-f5a4ff64c105
-rw-r--r-- | core/Db/Schema/Myisam.php | 1 | ||||
-rw-r--r-- | core/Tracker/Visit.php | 36 | ||||
-rwxr-xr-x | core/Updates/1.9.3-b8.php | 32 | ||||
-rw-r--r-- | core/Version.php | 4 | ||||
-rw-r--r-- | lang/en.php | 7 | ||||
-rw-r--r-- | plugins/SitesManager/API.php | 90 | ||||
-rw-r--r-- | plugins/SitesManager/Controller.php | 11 | ||||
-rw-r--r-- | plugins/SitesManager/SitesManager.php | 32 | ||||
-rw-r--r-- | plugins/SitesManager/templates/SitesManager.js | 21 | ||||
-rw-r--r-- | plugins/SitesManager/templates/SitesManager.tpl | 33 | ||||
-rw-r--r-- | tests/PHPUnit/Core/Tracker/VisitTest.php | 62 | ||||
-rwxr-xr-x | tests/PHPUnit/Integration/NoVisitTest.php | 20 | ||||
-rwxr-xr-x | tests/PHPUnit/Integration/OneVisitorTwoVisitsTest.php | 8 | ||||
-rw-r--r-- | tests/PHPUnit/Plugins/SitesManagerTest.php | 17 |
14 files changed, 346 insertions, 28 deletions
diff --git a/core/Db/Schema/Myisam.php b/core/Db/Schema/Myisam.php index fea2f54163..c28611d32c 100644 --- a/core/Db/Schema/Myisam.php +++ b/core/Db/Schema/Myisam.php @@ -89,6 +89,7 @@ class Piwik_Db_Schema_Myisam implements Piwik_Db_Schema_Interface currency CHAR( 3 ) NOT NULL, excluded_ips TEXT NOT NULL, excluded_parameters TEXT NOT NULL, + excluded_user_agents TEXT NOT NULL, `group` VARCHAR(250) NOT NULL, PRIMARY KEY(idsite) ) DEFAULT CHARSET=utf8 diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php index 1dd055f561..f44a267c6a 100644 --- a/core/Tracker/Visit.php +++ b/core/Tracker/Visit.php @@ -887,6 +887,16 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface } } + // Check if user agent should be excluded + if (!$excluded) + { + $excluded = $this->isUserAgentExcluded($ua); + if ($excluded) + { + printDebug("User agent excluded."); + } + } + if(!$excluded) { if( (isset($_SERVER["HTTP_X_PURPOSE"]) @@ -941,6 +951,32 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface } return false; } + + /** + * Returns true if the specified user agent should be excluded for the current site or not. + * + * Visits whose user agent string contains one of the excluded_user_agents strings for the + * site being tracked (or one of the global strings) will be excluded. + * + * @param string $ua The user agent string. + * @return bool + */ + protected function isUserAgentExcluded( $ua ) + { + $websiteAttributes = Piwik_Common::getCacheWebsiteAttributes($this->idsite); + if (!empty($websiteAttributes['excluded_user_agents'])) + { + foreach ($websiteAttributes['excluded_user_agents'] as $excludedUserAgent) + { + // if the excluded user agent string part is in this visit's user agent, this visit should be excluded + if (stripos($ua, $excludedUserAgent) !== false) + { + return true; + } + } + } + return false; + } /** * Returns the cookie name used for the Piwik Tracker cookie diff --git a/core/Updates/1.9.3-b8.php b/core/Updates/1.9.3-b8.php new file mode 100755 index 0000000000..c45ec4d9f8 --- /dev/null +++ b/core/Updates/1.9.3-b8.php @@ -0,0 +1,32 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * @version $Id$ + * + * @category Piwik + * @package Updates + */ + +/** + * @package Updates + */ +class Piwik_Updates_1_9_3_b8 extends Piwik_Updates +{ + static function getSql($schema = 'Myisam') + { + return array( + // ignore existing column name error (1060) + 'ALTER TABLE '.Piwik_Common::prefixTable('site') + . " ADD COLUMN excluded_user_agents TEXT NOT NULL AFTER excluded_parameters" => 1060, + ); + } + + static function update() + { + // add excluded_user_agents column to site table + Piwik_Updater::updateDatabase(__FILE__, self::getSql()); + } +} diff --git a/core/Version.php b/core/Version.php index 3822f51a65..c5aa99804d 100644 --- a/core/Version.php +++ b/core/Version.php @@ -21,5 +21,5 @@ final class Piwik_Version * Current Piwik version * @var string */ - const VERSION = '1.9.3-b7'; -}
\ No newline at end of file + const VERSION = '1.9.3-b8'; +} diff --git a/lang/en.php b/lang/en.php index 18cc8472db..1270f30580 100644 --- a/lang/en.php +++ b/lang/en.php @@ -1157,6 +1157,11 @@ And thank you for using Piwik!', 'SitesManager_SuperUserCan' => 'The Super User can also %s specify global settings%s for new websites.', 'SitesManager_ExcludedIps' => 'Excluded IPs', 'SitesManager_GlobalListExcludedIps' => 'Global list of Excluded IPs', + 'SitesManager_ExcludedUserAgents' => 'Excluded User Agents', + 'SitesManager_GlobalListExcludedUserAgents' => 'Global list of user agents to exclude', + 'SitesManager_GlobalListExcludedUserAgents_Desc' => 'If the visitor\'s user agent string contains any of the strings you specify, the visitor will be excluded from Piwik.', + 'SitesManager_GlobalExcludedUserAgentHelp1' => 'Enter the list of user agents to exclude from being tracked by Piwik.', + 'SitesManager_GlobalExcludedUserAgentHelp2' => 'You can use this to exclude some bots from being tracked.', 'SitesManager_ListOfIpsToBeExcludedOnAllWebsites' => 'The IPs below will be excluded from being tracked on all websites.', 'SitesManager_ExcludedParameters' => 'Excluded Parameters', 'SitesManager_GlobalListExcludedQueryParameters' => 'Global list of Query URL parameters to exclude', @@ -1194,6 +1199,8 @@ And thank you for using Piwik!', 'SitesManager_SearchKeywordLabel' => 'Query parameter', 'SitesManager_SearchCategoryLabel' => 'Category parameter', 'SitesManager_SearchUseDefault' => 'Use %sdefault%s Site Search parameters', + 'SitesManager_EnableSiteSpecificUserAgentExclude' => 'Enable website specific user agent exclusion.', + 'SitesManager_EnableSiteSpecificUserAgentExclude_Help' => 'If you need to exclude different user agents for different websites, check this box, click save and %1$sadd the user agents above%2$s.', 'TranslationsAdmin_PluginDescription' => 'Help translate Piwik into your language.', 'TranslationsAdmin_MenuTranslations' => 'Translations', 'TranslationsAdmin_MenuLanguages' => 'Languages', diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php index 8242893b21..9a8a95a77d 100644 --- a/plugins/SitesManager/API.php +++ b/plugins/SitesManager/API.php @@ -49,6 +49,8 @@ class Piwik_SitesManager_API const OPTION_EXCLUDED_QUERY_PARAMETERS_GLOBAL = 'SitesManager_ExcludedQueryParameters'; const OPTION_SEARCH_KEYWORD_QUERY_PARAMETERS_GLOBAL = 'SitesManager_SearchKeywordParameters'; const OPTION_SEARCH_CATEGORY_QUERY_PARAMETERS_GLOBAL = 'SitesManager_SearchCategoryParameters'; + const OPTION_EXCLUDED_USER_AGENTS_GLOBAL = 'SitesManager_ExcludedUserAgentsGlobal'; + const OPTION_SITE_SPECIFIC_USER_AGENT_EXCLUDE_ENABLE = 'SitesManager_EnableSiteSpecificUserAgentExclude'; /** * Returns the javascript tag for the given idSite. @@ -451,7 +453,19 @@ class Piwik_SitesManager_API * * @return int the website ID created */ - public function addSite( $siteName, $urls, $ecommerce = null, $siteSearch = null, $searchKeywordParameters = null, $searchCategoryParameters = null, $excludedIps = null, $excludedQueryParameters = null, $timezone = null, $currency = null, $group = null, $startDate = null ) + public function addSite( $siteName, + $urls, + $ecommerce = null, + $siteSearch = null, + $searchKeywordParameters = null, + $searchCategoryParameters = null, + $excludedIps = null, + $excludedQueryParameters = null, + $timezone = null, + $currency = null, + $group = null, + $startDate = null, + $excludedUserAgents = null ) { Piwik::checkUserIsSuperUser(); @@ -486,7 +500,8 @@ class Piwik_SitesManager_API ); $bind['excluded_ips'] = $this->checkAndReturnExcludedIps($excludedIps); - $bind['excluded_parameters'] = $this->checkAndReturnExcludedQueryParameters($excludedQueryParameters); + $bind['excluded_parameters'] = $this->checkAndReturnCommaSeparatedStringList($excludedQueryParameters); + $bind['excluded_user_agents'] = $this->checkAndReturnCommaSeparatedStringList($excludedUserAgents); $bind['timezone'] = $timezone; $bind['currency'] = $currency; $bind['ecommerce'] = (int)$ecommerce; @@ -745,6 +760,67 @@ class Piwik_SitesManager_API } /** + * Returns the list of user agent substrings to look for when excluding visits for + * all websites. If a visitor's user agent string contains one of these substrings, + * their visits will not be included. + * + * @return string Comma separated list of strings. + */ + public function getExcludedUserAgentsGlobal() + { + Piwik::checkUserHasSomeAdminAccess(); + return Piwik_GetOption(self::OPTION_EXCLUDED_USER_AGENTS_GLOBAL); + } + + /** + * Sets list of user agent substrings to look for when excluding visits. For more info, + * @see getExcludedUserAgentsGlobal. + * + * @param string $excludedUserAgents Comma separated list of strings. Each element is trimmed, + * and empty strings are removed. + */ + public function setGlobalExcludedUserAgents( $excludedUserAgents ) + { + Piwik::checkUserIsSuperUser(); + + // update option + $excludedUserAgents = $this->checkAndReturnCommaSeparatedStringList($excludedUserAgents); + Piwik_SetOption(self::OPTION_EXCLUDED_USER_AGENTS_GLOBAL, $excludedUserAgents); + + // make sure tracker cache will reflect change + Piwik_Common::deleteTrackerCache(); + } + + /** + * Returns true if site-specific user agent exclusion has been enabled. If it hasn't, + * only the global user agent substrings (see @setGlobalExcludedUserAgents) will be used. + * + * @return bool + */ + public function isSiteSpecificUserAgentExcludeEnabled() + { + Piwik::checkUserHasSomeAdminAccess(); + return (bool)Piwik_GetOption(self::OPTION_SITE_SPECIFIC_USER_AGENT_EXCLUDE_ENABLE); + } + + /** + * Sets whether it should be allowed to exclude different user agents for different + * websites. + * + * @param bool $enabled + */ + public function setSiteSpecificUserAgentExcludeEnabled( $enabled ) + { + Piwik::checkUserIsSuperUser(); + + // update option + Piwik_SetOption(self::OPTION_SITE_SPECIFIC_USER_AGENT_EXCLUDE_ENABLE, $enabled); + + // make sure tracker cache will reflect change + Piwik_Common::deleteTrackerCache(); + } + + /** * Sets list of URL query parameters to be excluded on all websites. * Will also apply to websites created in the future. * @@ -754,7 +830,7 @@ class Piwik_SitesManager_API public function setGlobalExcludedQueryParameters($excludedQueryParameters) { Piwik::checkUserIsSuperUser(); - $excludedQueryParameters = $this->checkAndReturnExcludedQueryParameters($excludedQueryParameters); + $excludedQueryParameters = $this->checkAndReturnCommaSeparatedStringList($excludedQueryParameters); Piwik_SetOption(self::OPTION_EXCLUDED_QUERY_PARAMETERS_GLOBAL, $excludedQueryParameters); Piwik_Common::deleteTrackerCache(); return true; @@ -865,7 +941,8 @@ class Piwik_SitesManager_API $timezone = null, $currency = null, $group = null, - $startDate = null) + $startDate = null, + $excludedUserAgents = null) { Piwik::checkUserHasAdminAccess($idSite); @@ -914,7 +991,8 @@ class Piwik_SitesManager_API $bind['ts_created'] = Piwik_Date::factory($startDate)->getDatetime(); } $bind['excluded_ips'] = $this->checkAndReturnExcludedIps($excludedIps); - $bind['excluded_parameters'] = $this->checkAndReturnExcludedQueryParameters($excludedQueryParameters); + $bind['excluded_parameters'] = $this->checkAndReturnCommaSeparatedStringList($excludedQueryParameters); + $bind['excluded_user_agents'] = $this->checkAndReturnCommaSeparatedStringList($excludedUserAgents); $bind['sitesearch'] = $this->checkSiteSearch($siteSearch); list($searchKeywordParameters, $searchCategoryParameters ) = $this->checkSiteSearchParameters($searchKeywordParameters, $searchCategoryParameters); @@ -939,7 +1017,7 @@ class Piwik_SitesManager_API Piwik_PostEvent('SitesManager.updateSite', $idSite); } - private function checkAndReturnExcludedQueryParameters($parameters) + private function checkAndReturnCommaSeparatedStringList($parameters) { $parameters = trim($parameters); if(empty($parameters)) diff --git a/plugins/SitesManager/Controller.php b/plugins/SitesManager/Controller.php index 18bfbb7d1e..54b5995c72 100644 --- a/plugins/SitesManager/Controller.php +++ b/plugins/SitesManager/Controller.php @@ -40,6 +40,7 @@ class Piwik_SitesManager_Controller extends Piwik_Controller_Admin $site['alias_urls'] = Piwik_SitesManager_API::getInstance()->getSiteUrlsFromId($site['idsite']); $site['excluded_ips'] = str_replace(',','<br/>', $site['excluded_ips']); $site['excluded_parameters'] = str_replace(',','<br/>', $site['excluded_parameters']); + $site['excluded_user_agents'] = str_replace(',', '<br/>', $site['excluded_user_agents']); } $view->adminSites = $sites; $view->adminSitesCount = count($sites); @@ -57,10 +58,15 @@ class Piwik_SitesManager_Controller extends Piwik_Controller_Admin $view->globalExcludedIps = str_replace(',',"\n", $excludedIpsGlobal); $excludedQueryParametersGlobal = Piwik_SitesManager_API::getInstance()->getExcludedQueryParametersGlobal(); $view->globalExcludedQueryParameters = str_replace(',',"\n", $excludedQueryParametersGlobal); + + $globalExcludedUserAgents = Piwik_SitesManager_API::getInstance()->getExcludedUserAgentsGlobal(); + $view->globalExcludedUserAgents = str_replace(',', "\n", $globalExcludedUserAgents); $view->globalSearchKeywordParameters = Piwik_SitesManager_API::getInstance()->getSearchKeywordParametersGlobal(); $view->globalSearchCategoryParameters = Piwik_SitesManager_API::getInstance()->getSearchCategoryParametersGlobal(); $view->isSearchCategoryTrackingEnabled = Piwik_PluginsManager::getInstance()->isPluginActivated('CustomVariables'); + $view->allowSiteSpecificUserAgentExclude = + Piwik_SitesManager_API::getInstance()->isSiteSpecificUserAgentExcludeEnabled(); $view->currentIpAddress = Piwik_IP::getIpFromHeader(); @@ -83,14 +89,19 @@ class Piwik_SitesManager_Controller extends Piwik_Controller_Admin $timezone = Piwik_Common::getRequestVar('timezone', false); $excludedIps = Piwik_Common::getRequestVar('excludedIps', false); $excludedQueryParameters = Piwik_Common::getRequestVar('excludedQueryParameters', false); + $excludedUserAgents = Piwik_Common::getRequestVar('excludedUserAgents', false); $currency = Piwik_Common::getRequestVar('currency', false); $searchKeywordParameters = Piwik_Common::getRequestVar('searchKeywordParameters', $default = ""); $searchCategoryParameters = Piwik_Common::getRequestVar('searchCategoryParameters', $default = ""); + $enableSiteUserAgentExclude = Piwik_Common::getRequestVar('enableSiteUserAgentExclude', $default = 0); Piwik_SitesManager_API::getInstance()->setDefaultTimezone($timezone); Piwik_SitesManager_API::getInstance()->setDefaultCurrency($currency); Piwik_SitesManager_API::getInstance()->setGlobalExcludedQueryParameters($excludedQueryParameters); Piwik_SitesManager_API::getInstance()->setGlobalExcludedIps($excludedIps); + Piwik_SitesManager_API::getInstance()->setGlobalExcludedUserAgents($excludedUserAgents); Piwik_SitesManager_API::getInstance()->setGlobalSearchParameters($searchKeywordParameters, $searchCategoryParameters); + Piwik_SitesManager_API::getInstance()->setSiteSpecificUserAgentExcludeEnabled( + $enableSiteUserAgentExclude == 1); $toReturn = $response->getResponse(); } catch(Exception $e ) { $toReturn = $response->getResponseException( $e ); diff --git a/plugins/SitesManager/SitesManager.php b/plugins/SitesManager/SitesManager.php index a05c9a2047..0df2dff87e 100644 --- a/plugins/SitesManager/SitesManager.php +++ b/plugins/SitesManager/SitesManager.php @@ -86,6 +86,7 @@ class Piwik_SitesManager extends Piwik_Plugin $website = Piwik_SitesManager_API::getInstance()->getSiteFromId($idSite); $array['excluded_ips'] = $this->getTrackerExcludedIps($website); $array['excluded_parameters'] = self::getTrackerExcludedQueryParameters($website); + $array['excluded_user_agents'] = self::getExcludedUserAgents($website); $array['sitesearch'] = $website['sitesearch']; $array['sitesearch_keyword_parameters'] = $this->getTrackerSearchKeywordParameters($website); $array['sitesearch_category_parameters'] = $this->getTrackerSearchCategoryParameters($website); @@ -132,6 +133,23 @@ class Piwik_SitesManager extends Piwik_Plugin } return $ipRanges; } + + /** + * Returns the array of excluded user agent substrings for a site. Filters out + * any garbage data & trims each entry. + * + * @param array $website The full set of information for a site. + * @return array + */ + private static function getExcludedUserAgents( $website ) + { + $excludedUserAgents = Piwik_SitesManager_API::getInstance()->getExcludedUserAgentsGlobal(); + if (Piwik_SitesManager_API::getInstance()->isSiteSpecificUserAgentExcludeEnabled()) + { + $excludedUserAgents .= ','.$website['excluded_user_agents']; + } + return self::filterBlankFromCommaSepList($excludedUserAgents); + } /** * Returns the array of URL query parameters to exclude from URLs @@ -144,7 +162,19 @@ class Piwik_SitesManager extends Piwik_Plugin $globalExcludedQueryParameters = Piwik_SitesManager_API::getInstance()->getExcludedQueryParametersGlobal(); $excludedQueryParameters .= ',' . $globalExcludedQueryParameters; - $parameters = explode(',', $excludedQueryParameters); + return self::filterBlankFromCommaSepList($excludedQueryParameters); + } + + /** + * Trims each element of a comma-separated list of strings, removes empty elements and + * returns the result (as an array). + * + * @param string $parameters The unfiltered list. + * @return array The filtered list of strings as an array. + */ + private function filterBlankFromCommaSepList( $parameters ) + { + $parameters = explode(',', $parameters); $parameters = array_filter($parameters, 'strlen'); $parameters = array_unique($parameters); return $parameters; diff --git a/plugins/SitesManager/templates/SitesManager.js b/plugins/SitesManager/templates/SitesManager.js index 391c990528..f2473689ce 100644 --- a/plugins/SitesManager/templates/SitesManager.js +++ b/plugins/SitesManager/templates/SitesManager.js @@ -44,8 +44,10 @@ function SitesManager ( _timezones, _currencies, _defaultTimezone, _defaultCurre var timezone = encodeURIComponent($(row).find('#timezones option:selected').val()); var currency = encodeURIComponent($(row).find('#currencies option:selected').val()); var excludedQueryParameters = $(row).find('textarea#excludedQueryParameters').val(); - var ecommerce = encodeURIComponent($(row).find('#ecommerce option:selected').val()); excludedQueryParameters = piwikHelper.getApiFormatTextarea(excludedQueryParameters); + var excludedUserAgents = $(row).find('textarea#excludedUserAgents').val(); + excludedUserAgents = piwikHelper.getApiFormatTextarea(excludedUserAgents); + var ecommerce = encodeURIComponent($(row).find('#ecommerce option:selected').val()); var sitesearch = encodeURIComponent($(row).find('#sitesearch option:selected').val()); var searchKeywordParameters = $('input#searchKeywordParameters').val(); var searchCategoryParameters = $('input#searchCategoryParameters').val(); @@ -61,6 +63,7 @@ function SitesManager ( _timezones, _currencies, _defaultTimezone, _defaultCurre request += '&ecommerce='+ecommerce; request += '&excludedIps='+excludedIps; request += '&excludedQueryParameters='+excludedQueryParameters; + request += '&excludedUserAgents='+excludedUserAgents; request += '&siteSearch='+sitesearch; request += '&searchKeywordParameters='+searchKeywordParameters; request += '&searchCategoryParameters='+searchCategoryParameters; @@ -94,6 +97,8 @@ function SitesManager ( _timezones, _currencies, _defaultTimezone, _defaultCurre excludedIps = piwikHelper.getApiFormatTextarea(excludedIps); var excludedQueryParameters = $(row).find('textarea#excludedQueryParameters').val(); excludedQueryParameters = piwikHelper.getApiFormatTextarea(excludedQueryParameters); + var excludedUserAgents = $(row).find('textarea#excludedUserAgents').val(); + excludedUserAgents = piwikHelper.getApiFormatTextarea(excludedUserAgents); var timezone = encodeURIComponent($(row).find('#timezones option:selected').val()); var currency = encodeURIComponent($(row).find('#currencies option:selected').val()); var ecommerce = encodeURIComponent($(row).find('#ecommerce option:selected').val()); @@ -112,6 +117,7 @@ function SitesManager ( _timezones, _currencies, _defaultTimezone, _defaultCurre request += '&ecommerce='+ecommerce; request += '&excludedIps='+excludedIps; request += '&excludedQueryParameters='+excludedQueryParameters; + request += '&excludedUserAgents='+excludedUserAgents; request += '&siteSearch='+sitesearch; request += '&searchKeywordParameters='+searchKeywordParameters; request += '&searchCategoryParameters='+searchCategoryParameters; @@ -132,8 +138,11 @@ function SitesManager ( _timezones, _currencies, _defaultTimezone, _defaultCurre excludedIps = piwikHelper.getApiFormatTextarea(excludedIps); var excludedQueryParameters = $('textarea#globalExcludedQueryParameters').val(); excludedQueryParameters = piwikHelper.getApiFormatTextarea(excludedQueryParameters); + var globalExcludedUserAgents = $('textarea#globalExcludedUserAgents').val(); + globalExcludedUserAgents = piwikHelper.getApiFormatTextarea(globalExcludedUserAgents); var searchKeywordParameters = $('input#globalSearchKeywordParameters').val(); var searchCategoryParameters = $('input#globalSearchCategoryParameters').val(); + var enableSiteUserAgentExclude = $('input#enableSiteUserAgentExclude').is(':checked') ? 1 : 0; var request = ''; request += 'module=SitesManager'; request += '&action=setGlobalSettings'; @@ -142,6 +151,8 @@ function SitesManager ( _timezones, _currencies, _defaultTimezone, _defaultCurre request += '¤cy='+currency; request += '&excludedIps='+excludedIps; request += '&excludedQueryParameters='+excludedQueryParameters; + request += '&excludedUserAgents='+globalExcludedUserAgents; + request += '&enableSiteUserAgentExclude='+enableSiteUserAgentExclude; request += '&searchKeywordParameters='+searchKeywordParameters; request += '&searchCategoryParameters='+searchCategoryParameters; request += '&token_auth=' + piwik.token_auth; @@ -163,6 +174,7 @@ function SitesManager ( _timezones, _currencies, _defaultTimezone, _defaultCurre <td><textarea cols="25" rows="3" id="urls">http://siteUrl.com/\nhttp://siteUrl2.com/</textarea><br />'+aliasUrlsHelp+'</td>\ <td><textarea cols="20" rows="4" id="excludedIps"></textarea><br />'+excludedIpHelp+'</td>\ <td><textarea cols="20" rows="4" id="excludedQueryParameters"></textarea><br />'+excludedQueryParametersHelp+'</td>\ + <td><textarea cols="20" rows="4" id="excludedUserAgents"></textarea><br />'+excludedUserAgentsHelp+'</td>\ <td>'+getSitesearchSelector(false)+'</td>\ <td>'+getTimezoneSelector(defaultTimezone)+'<br />' + timezoneHelp + '</td>\ <td>'+getCurrencySelector(defaultCurrency)+'<br />' + currencyHelp + '</td>\ @@ -256,6 +268,12 @@ function SitesManager ( _timezones, _currencies, _defaultTimezone, _defaultCurre contentAfter += '<br />'+excludedQueryParametersHelp; $(n).html(contentAfter); } + else if (idName == 'excludedUserAgents') + { + var contentAfter = '<textarea cols="20" rows="4" id="excludedUserAgents">' + + contentBefore.replace(/<br *\/? *>/gi,"\n")+'</textarea><br />'+excludedUserAgentsHelp; + $(n).html(contentAfter); + } else if(idName == 'timezone') { var contentAfter = getTimezoneSelector(contentBefore); @@ -434,3 +452,4 @@ function onClickSiteSearchUseDefault() $('#sitesearchIntro').show(); } } + diff --git a/plugins/SitesManager/templates/SitesManager.tpl b/plugins/SitesManager/templates/SitesManager.tpl index d16539fe7d..0a172540b7 100644 --- a/plugins/SitesManager/templates/SitesManager.tpl +++ b/plugins/SitesManager/templates/SitesManager.tpl @@ -37,7 +37,15 @@ var aliasUrlsHelp = '{'SitesManager_AliasUrlHelp'|translate|inlineHelp|escape:ja {'SitesManager_PiwikWillAutomaticallyExcludeCommonSessionParameters'|translate:"phpsessid, sessionid, ..."} {/capture} {assign var=excludedQueryParametersHelp value=$excludedQueryParametersHelp|inlineHelp} + +{capture assign=excludedUserAgentsHelp} + {'SitesManager_GlobalExcludedUserAgentHelp1'|translate} + <br/><br/> + {'SitesManager_GlobalListExcludedUserAgents_Desc'|translate} {'SitesManager_GlobalExcludedUserAgentHelp2'|translate} +{/capture} +{assign var=excludedUserAgentsHelp value=$excludedUserAgentsHelp|inlineHelp} var excludedQueryParametersHelp = '{$excludedQueryParametersHelp|escape:javascript}'; +var excludedUserAgentsHelp = '{$excludedUserAgentsHelp|escape:javascript}'; var timezoneHelp = '{$timezoneHelpPlain|inlineHelp|escape:javascript}'; var currencyHelp = '{$currencyHelpPlain|escape:javascript}'; var ecommerceHelp = '{$ecommerceHelpPlain|inlineHelp|escape:javascript}'; @@ -140,6 +148,7 @@ vertical-align:middle; <th>{'SitesManager_Urls'|translate}</th> <th>{'SitesManager_ExcludedIps'|translate}</th> <th>{'SitesManager_ExcludedParameters'|translate|replace:" ":"<br />"}</th> + <th id='exclude-user-agent-header' {if !$allowSiteSpecificUserAgentExclude}style="display:none"{/if}>{'SitesManager_ExcludedUserAgents'|translate}</th> <th>{'Actions_SubmenuSitesearch'|translate}</th> <th>{'SitesManager_Timezone'|translate}</th> <th>{'SitesManager_Currency'|translate}</th> @@ -156,13 +165,14 @@ vertical-align:middle; <td id="siteName" class="editableSite">{$site.name}</td> <td id="urls" class="editableSite">{foreach from=$site.alias_urls item=url}{$url|replace:"http://":""}<br />{/foreach}</td> <td id="excludedIps" class="editableSite">{foreach from=$site.excluded_ips item=ip}{$ip}<br />{/foreach}</td> - <td id="excludedQueryParameters" class="editableSite">{foreach from=$site.excluded_parameters item=parameter}{$parameter}<br />{/foreach}</td> + <td id="excludedQueryParameters" class="editableSite">{foreach from=$site.excluded_parameters item=parameter}{$parameter}<br />{/foreach}</td> + <td id="excludedUserAgents" class="editableSite" {if !$allowSiteSpecificUserAgentExclude}style="display:none"{/if}>{foreach from=$site.excluded_user_agents item=ua}{$ua}<br />{/foreach}</td> <td id="sitesearch" class="editableSite">{if $site.sitesearch}<span class='sitesearchActive'>{'General_Yes'|translate}</span>{else}<span class='sitesearchInactive'>-</span>{/if}<span class='sskp' sitesearch_keyword_parameters="{$site.sitesearch_keyword_parameters|escape:'html'}" sitesearch_category_parameters="{$site.sitesearch_category_parameters|escape:'html'}" id="sitesearch_parameters"></span></td> <td id="timezone" class="editableSite">{$site.timezone}</td> <td id="currency" class="editableSite">{$site.currency}</td> <td id="ecommerce" class="editableSite">{if $site.ecommerce}<span class='ecommerceActive'>{'General_Yes'|translate}</span>{else}<span class='ecommerceInactive'>-</span>{/if}</td> - <td><span id="row{$i}" class='editSite link_but'><img src='themes/default/images/ico_edit.png' title="{'General_Edit'|translate}" border="0"/> {'General_Edit'|translate}</span></td> - <td><span id="row{$i}" class="deleteSite link_but"><img src='themes/default/images/ico_delete.png' title="{'General_Delete'|translate}" border="0" /> {'General_Delete'|translate}</span></td> + <td><span id="row{$site.idsite}" class='editSite link_but'><img src='themes/default/images/ico_edit.png' title="{'General_Edit'|translate}" border="0"/> {'General_Edit'|translate}</span></td> + <td><span id="row{$site.idsite}" class="deleteSite link_but"><img src='themes/default/images/ico_delete.png' title="{'General_Delete'|translate}" border="0" /> {'General_Delete'|translate}</span></td> <td><a href='{url action=displayJavascriptCode idSite=$site.idsite updated=false}'>{'SitesManager_ShowTrackingTag'|translate}</a></td> </tr> {/foreach} @@ -209,6 +219,23 @@ vertical-align:middle; </textarea> </td><td><label for="globalExcludedQueryParameters">{$excludedQueryParametersHelp}</label> </td></tr> + + {* global excluded user agents *} + <tr><td colspan="2"> + <b>{'SitesManager_GlobalListExcludedUserAgents'|translate}</b> + <p>{'SitesManager_GlobalListExcludedUserAgents_Desc'|translate}</p> + </td></tr> + + <tr><td> + <textarea cols="30" rows="3" id="globalExcludedUserAgents">{$globalExcludedUserAgents}</textarea> + </td><td><label for="globalExcludedUserAgents">{$excludedUserAgentsHelp}</label> + </td></tr> + + <tr><td> + <input type="checkbox" id="enableSiteUserAgentExclude" name="enableSiteUserAgentExclude" {if $allowSiteSpecificUserAgentExclude}checked="checked"{/if}/><label for="enableSiteUserAgentExclude">{'SitesManager_EnableSiteSpecificUserAgentExclude'|translate}</label> + <span id='enableSiteUserAgentExclude-loading' class='loadingPiwik' style='display:none'><img src='./themes/default/images/loading-blue.gif' /></span> + </td><td>{'SitesManager_EnableSiteSpecificUserAgentExclude_Help'|translate:'<a href="#editSites">':'</a>'|inlineHelp} + </td></tr> <tr><td colspan="2"> <a name='globalSiteSearch'></a><b>{'SitesManager_TrackingSiteSearch'|translate}</b> diff --git a/tests/PHPUnit/Core/Tracker/VisitTest.php b/tests/PHPUnit/Core/Tracker/VisitTest.php index 6c75c534d9..0d7b8067bc 100644 --- a/tests/PHPUnit/Core/Tracker/VisitTest.php +++ b/tests/PHPUnit/Core/Tracker/VisitTest.php @@ -82,11 +82,65 @@ class Tracker_VisitTest extends DatabaseTestCase $this->assertSame($expected, $visit->public_isVisitorIpExcluded($testIpIsExcluded)); } } + + /** + * Dataprovider for testIsVisitorUserAgentExcluded. + */ + public function getExcludedUserAgentTestData() + { + return array( + array('', array( + 'whatever' => false, + '' => false, + 'nlksdjfsldkjfsa' => false, + )), + array('mozilla', array( + 'this has mozilla in it' => true, + 'this doesn\'t' => false, + 'partial presence: mozi' => false, + )), + array('cHrOmE,notinthere,&^%', array( + 'chrome is here' => true, + 'CHROME is here' => true, + '12&^%345' => true, + 'sfasdf' => false, + )), + ); + } + + /** + * @group Core + * @group Tracker + * @group Tracker_Visit + * @dataProvider getExcludedUserAgentTestData + */ + public function testIsVisitorUserAgentExcluded($excludedUserAgent, $tests) + { + Piwik_SitesManager_API::getInstance()->setSiteSpecificUserAgentExcludeEnabled(true); + + $visit = new Test_Piwik_TrackerVisit_public(); + $idsite = Piwik_SitesManager_API::getInstance()->addSite("name","http://piwik.net/",$ecommerce=0, + $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, $excludedIp=null, + $excludedQueryParameters = null, $timezone = null, $currency = null, $group = null, $startDate = null, + $excludedUserAgent); + $visit->setRequest(array('idsite' => $idsite)); + + // test that user agents that contain excluded user agent strings are excluded + foreach ($tests as $ua => $expected) + { + $this->assertSame($expected, $visit->public_isUserAgentExcluded($ua), "Result if isUserAgentExcluded('$ua') was not ".($expected?'true':'false')."."); + } + } } class Test_Piwik_TrackerVisit_public extends Piwik_Tracker_Visit { - public function public_isVisitorIpExcluded( $ip ) - { - return $this->isVisitorIpExcluded($ip); - } + public function public_isVisitorIpExcluded( $ip ) + { + return $this->isVisitorIpExcluded($ip); + } + + public function public_isUserAgentExcluded( $ua ) + { + return $this->isUserAgentExcluded($ua); + } } diff --git a/tests/PHPUnit/Integration/NoVisitTest.php b/tests/PHPUnit/Integration/NoVisitTest.php index 6d52163cd6..0a4280cf8f 100755 --- a/tests/PHPUnit/Integration/NoVisitTest.php +++ b/tests/PHPUnit/Integration/NoVisitTest.php @@ -67,6 +67,9 @@ class Test_Piwik_Integration_NoVisit extends IntegrationTestCase { $dateTime = self::$dateTime; $idSite = self::$idSite; + + Piwik_SitesManager_API::getInstance()->setSiteSpecificUserAgentExcludeEnabled(true); + Piwik_SitesManager_API::getInstance()->setGlobalExcludedUserAgents('globalexcludeduseragent'); /* // Trigger invalid website @@ -93,16 +96,27 @@ class Test_Piwik_Integration_NoVisit extends IntegrationTestCase // Test IP Exclusion works with or without IP exclusion foreach (array(false, true) as $enable) { + $excludedIp = '154.1.12.34'; + Piwik_SitesManager_API::getInstance()->updateSite($idSite, 'new site name', $url = array('http://site.com'), $ecommerce = 0, $ss = 1, $ss_kwd = '', $ss_cat = '', $excludedIp . ',1.2.3.4', $excludedQueryParameters = null, $timezone = null, $currency = null, $group = null, $startDate = null, $excludedUserAgents = 'excludeduseragentstring'); + // Enable IP Anonymization $t->DEBUG_APPEND_URL = '&forceIpAnonymization=' . (int)$enable; + // test with excluded User Agent + $t->setUserAgent('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 (.NET CLR 3.5.30729) (excludeduseragentstring)'); + $t->setIp('211.1.2.3'); + self::checkResponse($t->doTrackPageView('visit from excluded User Agent')); + + // test w/ global excluded User Agent + $t->setUserAgent('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 (.NET CLR 3.5.30729) (globalexcludeduseragent)'); + $t->setIp('211.1.2.3'); + self::checkResponse($t->doTrackPageView('visit from global excluded User Agent')); + // test with excluded IP $t->setUserAgent('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 (.NET CLR 3.5.30729)'); // restore normal user agent - $excludedIp = '154.1.12.34'; - Piwik_SitesManager_API::getInstance()->updateSite($idSite, 'new site name', $url = array('http://site.com'), $ecommerce = 0, $ss = 1, $ss_kwd = '', $ss_cat = '', $excludedIp . ',1.2.3.4'); $t->setIp($excludedIp); self::checkResponse($t->doTrackPageView('visit from IP excluded')); - + // test with global list of excluded IPs $excludedIpBis = '145.5.3.4'; Piwik_SitesManager_API::getInstance()->setGlobalExcludedIps($excludedIpBis); diff --git a/tests/PHPUnit/Integration/OneVisitorTwoVisitsTest.php b/tests/PHPUnit/Integration/OneVisitorTwoVisitsTest.php index 5b88484fb8..3672c66a82 100755 --- a/tests/PHPUnit/Integration/OneVisitorTwoVisitsTest.php +++ b/tests/PHPUnit/Integration/OneVisitorTwoVisitsTest.php @@ -181,6 +181,8 @@ class Test_Piwik_Integration_OneVisitorTwoVisits extends IntegrationTestCase $dateTime = self::$dateTime; $idSite = self::$idSite; + Piwik_SitesManager_API::getInstance()->setSiteSpecificUserAgentExcludeEnabled(false); + $t = self::getTracker($idSite, $dateTime, $defaultInit = true); $t->disableCookieSupport(); @@ -191,7 +193,11 @@ class Test_Piwik_Integration_OneVisitorTwoVisits extends IntegrationTestCase $parameterToExclude = 'excluded_parameter'; Piwik_SitesManager_API::getInstance()->updateSite($idSite, 'new name', $url = array('http://site.com'), $ecommerce = 0, $siteSearch = null, $searchKeywordParameters = null, - $searchCategoryParameters = null, $excludedIps = null, $parameterToExclude . ',anotherParameter'); + $searchCategoryParameters = null, $excludedIps = null, $parameterToExclude . ',anotherParameter', + $timezone = null, $currency = null, $group = null, $startDate = null, + // test that visit won't be excluded since site-specific exclude is not enabled + $excludedUserAgents = 'mozilla' + ); // Record 1st page view $urlPage1 = 'http://example.org/index.htm?excluded_Parameter=SHOULD_NOT_DISPLAY¶meter=Should display'; diff --git a/tests/PHPUnit/Plugins/SitesManagerTest.php b/tests/PHPUnit/Plugins/SitesManagerTest.php index 521242b149..7559cd3798 100644 --- a/tests/PHPUnit/Plugins/SitesManagerTest.php +++ b/tests/PHPUnit/Plugins/SitesManagerTest.php @@ -78,9 +78,11 @@ class SitesManagerTest extends DatabaseTestCase $currency = 'EUR'; $excludedQueryParameters = 'p1,P2, P33333'; $expectedExcludedQueryParameters = 'p1,P2,P33333'; + $excludedUserAgents = " p1,P2, \nP3333 "; + $expectedExcludedUserAgents = "p1,P2,P3333"; $idsite = Piwik_SitesManager_API::getInstance()->addSite("name","http://piwik.net/", $ecommerce = 1, $siteSearch = 1, $searchKeywordParameters = 'search,param', $searchCategoryParameters = 'cat,category', - $ips, $excludedQueryParameters,$timezone, $currency); + $ips, $excludedQueryParameters,$timezone, $currency, $group = null, $startDate = null, $excludedUserAgents); $siteInfo = Piwik_SitesManager_API::getInstance()->getSiteFromId($idsite); $this->assertEquals($ips, $siteInfo['excluded_ips']); $this->assertEquals($timezone, $siteInfo['timezone']); @@ -92,6 +94,7 @@ class SitesManagerTest extends DatabaseTestCase $this->assertEquals($searchKeywordParameters, $siteInfo['sitesearch_keyword_parameters']); $this->assertEquals($searchCategoryParameters, $siteInfo['sitesearch_category_parameters']); $this->assertEquals($expectedExcludedQueryParameters, $siteInfo['excluded_parameters']); + $this->assertEquals($expectedExcludedUserAgents, $siteInfo['excluded_user_agents']); } /** @@ -511,8 +514,8 @@ class SitesManagerTest extends DatabaseTestCase $idsite = Piwik_SitesManager_API::getInstance()->addSite("site3",array("http://piwik.org")); $resultWanted = array( - 0 => array("idsite" => 1, "name" => "site1", "main_url" =>"http://piwik.net", "ecommerce" => 0, "excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), - 1 => array("idsite" => 3, "name" => "site3", "main_url" =>"http://piwik.org", "ecommerce" => 0,"excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), + 0 => array("idsite" => 1, "name" => "site1", "main_url" =>"http://piwik.net", "ecommerce" => 0, "excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), + 1 => array("idsite" => 3, "name" => "site3", "main_url" =>"http://piwik.org", "ecommerce" => 0,"excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), ); FakeAccess::setIdSitesAdmin (array(1,3)); @@ -553,8 +556,8 @@ class SitesManagerTest extends DatabaseTestCase $idsite = Piwik_SitesManager_API::getInstance()->addSite("site3",array("http://piwik.org")); $resultWanted = array( - 0 => array("idsite" => 1, "name" => "site1", "main_url" =>"http://piwik.net", "ecommerce" => 0, 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '',"excluded_ips" => "", 'excluded_parameters' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), - 1 => array("idsite" => 3, "name" => "site3", "main_url" =>"http://piwik.org", "ecommerce" => 0, 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '',"excluded_ips" => "", 'excluded_parameters' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), + 0 => array("idsite" => 1, "name" => "site1", "main_url" =>"http://piwik.net", "ecommerce" => 0, 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '',"excluded_ips" => "", 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), + 1 => array("idsite" => 3, "name" => "site3", "main_url" =>"http://piwik.org", "ecommerce" => 0, 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '',"excluded_ips" => "", 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), ); FakeAccess::setIdSitesView (array(1,3)); @@ -595,8 +598,8 @@ class SitesManagerTest extends DatabaseTestCase $idsite = Piwik_SitesManager_API::getInstance()->addSite("site3",array("http://piwik.org")); $resultWanted = array( - 0 => array("idsite" => 1, "name" => "site1", "main_url" =>"http://piwik.net", "ecommerce" => 1,"excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), - 1 => array("idsite" => 3, "name" => "site3", "main_url" =>"http://piwik.org", "ecommerce" => 0,"excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), + 0 => array("idsite" => 1, "name" => "site1", "main_url" =>"http://piwik.net", "ecommerce" => 1,"excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), + 1 => array("idsite" => 3, "name" => "site3", "main_url" =>"http://piwik.org", "ecommerce" => 0,"excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => ''), ); FakeAccess::setIdSitesView (array(1,3)); |