diff --git a/core/Db/Schema/Mysql.php b/core/Db/Schema/Mysql.php index 8402dc5bd1441a8014c16d49155c7bf288c525f8..8b554e1ae40e217272c7c7a8f478d4732924dbbe 100644 --- a/core/Db/Schema/Mysql.php +++ b/core/Db/Schema/Mysql.php @@ -92,6 +92,7 @@ class Mysql implements SchemaInterface sitesearch_category_parameters TEXT NOT NULL, timezone VARCHAR( 50 ) NOT NULL, currency CHAR( 3 ) NOT NULL, + exclude_unknown_urls TINYINT(1) DEFAULT 0, excluded_ips TEXT NOT NULL, excluded_parameters TEXT NOT NULL, excluded_user_agents TEXT NOT NULL, diff --git a/core/Tracker/VisitExcluded.php b/core/Tracker/VisitExcluded.php index 028c44460cfaf6569a044fb514a9cc72e90220ff..0bc6fa2fbb599714a789bcbde93ae3072114f86b 100644 --- a/core/Tracker/VisitExcluded.php +++ b/core/Tracker/VisitExcluded.php @@ -128,6 +128,14 @@ class VisitExcluded } } + // Check if request URL is excluded + if (!$excluded) { + $excluded = $this->isUrlExcluded(); + if ($excluded) { + Common::printDebug("Unknown URL is not allowed to track."); + } + } + if (!$excluded) { if ($this->isPrefetchDetected()) { $excluded = true; @@ -274,6 +282,27 @@ class VisitExcluded return false; } + /** + * Checks if request URL is excluded + * @return bool + */ + protected function isUrlExcluded() + { + $site = Cache::getCacheWebsiteAttributes($this->idSite); + + if (!empty($site['exclude_unknown_urls']) && !empty($site['hosts'])) { + $trackingHost = parse_url($this->request->getParam('url'), PHP_URL_HOST); + foreach ($site['hosts'] as $siteHost) { + if ($trackingHost == $siteHost || (substr($trackingHost, -strlen($siteHost) - 1) === ('.' . $siteHost))) { + return false; + } + } + return true; + } + + return false; + } + /** * Returns true if the specified user agent should be excluded for the current site or not. * diff --git a/core/Updates/2.15.0-b3.php b/core/Updates/2.15.0-b3.php new file mode 100644 index 0000000000000000000000000000000000000000..374563c6fb2d486b47502134592702c2761259f1 --- /dev/null +++ b/core/Updates/2.15.0-b3.php @@ -0,0 +1,32 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ + +namespace Piwik\Updates; + +use Piwik\Common; +use Piwik\Updater; +use Piwik\Updates; + + +class Updates_2_15_0_b3 extends Updates +{ + public function getMigrationQueries(Updater $updater) + { + $updateSql = array( + 'ALTER TABLE `' . Common::prefixTable('site') + . '` ADD COLUMN `exclude_unknown_urls` TINYINT(1) DEFAULT 0 AFTER `currency`' => array(1060) + ); + return $updateSql; + } + + public function doUpdate(Updater $updater) + { + $updater->executeMigrationQueries(__FILE__, $this->getMigrationQueries($updater)); + } +} diff --git a/core/Version.php b/core/Version.php index 6c21a7ade53ad61c0345931c21a729c3d7802f10..36a823aef3c4911b3fb7ba6b579c9a57318168c4 100644 --- a/core/Version.php +++ b/core/Version.php @@ -20,7 +20,7 @@ final class Version * The current Piwik version. * @var string */ - const VERSION = '2.15.0-b2'; + const VERSION = '2.15.0-b3'; public function isStableVersion($version) { diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php index 8c182c47a519598de92262124b3ff7360a3e05fe..7c2715fa2b4d74a4e1a9dd694a81ed47ae3970c1 100644 --- a/plugins/SitesManager/API.php +++ b/plugins/SitesManager/API.php @@ -506,6 +506,7 @@ class API extends \Piwik\Plugin\API * @param array|null $settings JSON serialized settings eg {settingName: settingValue, ...} * @see getKeepURLFragmentsGlobal. * @param string $type The website type, defaults to "website" if not set. + * @param bool|null $excludeUnknownUrls Track only URL matching one of website URLs * * @return int the website ID created */ @@ -524,7 +525,8 @@ class API extends \Piwik\Plugin\API $excludedUserAgents = null, $keepURLFragments = null, $type = null, - $settings = null) + $settings = null, + $excludeUnknownUrls = null) { Piwik::checkUserHasSuperUserAccess(); @@ -555,6 +557,7 @@ class API extends \Piwik\Plugin\API $bind = array('name' => $siteName, 'main_url' => $url); + $bind['exclude_unknown_urls'] = (int)$excludeUnknownUrls; $bind['excluded_ips'] = $this->checkAndReturnExcludedIps($excludedIps); $bind['excluded_parameters'] = $this->checkAndReturnCommaSeparatedStringList($excludedQueryParameters); $bind['excluded_user_agents'] = $this->checkAndReturnCommaSeparatedStringList($excludedUserAgents); @@ -1087,6 +1090,7 @@ class API extends \Piwik\Plugin\API * will be removed. If 0, the default global behavior will be used. * @param string $type The Website type, default value is "website" * @param array|null $settings JSON serialized settings eg {settingName: settingValue, ...} + * @param bool|null $excludeUnknownUrls Track only URL matching one of website URLs * @throws Exception * @see getKeepURLFragmentsGlobal. If null, the existing value will * not be modified. @@ -1109,7 +1113,8 @@ class API extends \Piwik\Plugin\API $excludedUserAgents = null, $keepURLFragments = null, $type = null, - $settings = null) + $settings = null, + $excludeUnknownUrls = null) { Piwik::checkUserHasAdminAccess($idSite); @@ -1156,6 +1161,7 @@ class API extends \Piwik\Plugin\API if (!is_null($startDate)) { $bind['ts_created'] = Date::factory($startDate)->getDatetime(); } + $bind['exclude_unknown_urls'] = (int)$excludeUnknownUrls; $bind['excluded_ips'] = $this->checkAndReturnExcludedIps($excludedIps); $bind['excluded_parameters'] = $this->checkAndReturnCommaSeparatedStringList($excludedQueryParameters); $bind['excluded_user_agents'] = $this->checkAndReturnCommaSeparatedStringList($excludedUserAgents); diff --git a/plugins/SitesManager/SitesManager.php b/plugins/SitesManager/SitesManager.php index a2982346406667332468f759113690a355996ee7..16c330d6c1cef067e306f0b28d9120fd5e2fdb90 100644 --- a/plugins/SitesManager/SitesManager.php +++ b/plugins/SitesManager/SitesManager.php @@ -117,6 +117,7 @@ class SitesManager extends \Piwik\Plugin $array['hosts'] = $this->getTrackerHosts($idSite); $website = API::getInstance()->getSiteFromId($idSite); + $array['exclude_unknown_urls'] = $website['exclude_unknown_urls']; $array['excluded_ips'] = $this->getTrackerExcludedIps($website); $array['excluded_parameters'] = self::getTrackerExcludedQueryParameters($website); $array['excluded_user_agents'] = self::getExcludedUserAgents($website); @@ -286,6 +287,8 @@ class SitesManager extends \Piwik\Plugin $translationKeys[] = "SitesManager_Currency"; $translationKeys[] = "SitesManager_ShowTrackingTag"; $translationKeys[] = "SitesManager_AliasUrlHelp"; + $translationKeys[] = "SitesManager_OnlyMatchedUrlsAllowed"; + $translationKeys[] = "SitesManager_OnlyMatchedUrlsAllowedHelp"; $translationKeys[] = "SitesManager_KeepURLFragmentsLong"; $translationKeys[] = "SitesManager_HelpExcludedIps"; $translationKeys[] = "SitesManager_ListOfQueryParametersToExclude"; diff --git a/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js b/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js index 21dc868f7ae59c62d920a00c8917d69be5105b8a..d759ec940f02ad77be9118b9b22fbf1d0f1ab66e 100644 --- a/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js +++ b/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js @@ -111,6 +111,7 @@ searchKeywordParameters: sendSiteSearchKeywordParams ? $scope.site.sitesearch_keyword_parameters.join(',') : null, searchCategoryParameters: sendSearchCategoryParameters ? $scope.site.sitesearch_category_parameters.join(',') : null, urls: $scope.site.alias_urls, + excludeUnknownUrls: $scope.site.exclude_unknown_urls, settings: flatSettings }, 'POST'); @@ -133,6 +134,7 @@ "http://siteUrl.com/", "http://siteUrl2.com/" ]; + $scope.site.exclude_unknown_urls = 0; $scope.site.keep_url_fragment = "0"; $scope.site.excluded_ips = []; $scope.site.excluded_parameters = []; diff --git a/plugins/SitesManager/lang/en.json b/plugins/SitesManager/lang/en.json index 20977db504988f9b8ae4d50ef0ec1290d82fd901..e3ae0d3feba76e806ab88c51b1317f6f6127b875 100644 --- a/plugins/SitesManager/lang/en.json +++ b/plugins/SitesManager/lang/en.json @@ -74,6 +74,8 @@ "TrackingTags": "Tracking code for %s", "Urls": "URLs", "UTCTimeIs": "UTC time is %s.", + "OnlyMatchedUrlsAllowed": "Only track visits and actions when the action URL starts with one of the above URLs.", + "OnlyMatchedUrlsAllowedHelp": "When enabled, Piwik will only track internal actions when the Page URL is one of the known URLs for your website. This prevents people from spamming your analytics with URLs for other websites.", "WebsitesManagement": "Websites Management", "XManagement": "Manage %s", "ChooseMeasurableTypeHeadline": "What would you like to measure?", diff --git a/plugins/SitesManager/templates/sites-list/site-fields.html b/plugins/SitesManager/templates/sites-list/site-fields.html index 888d9f7b1fdf6ebd3109a0d5ca9f874ba9c16177..dada85cc225cb49be691ba4123e3205adb31482b 100644 --- a/plugins/SitesManager/templates/sites-list/site-fields.html +++ b/plugins/SitesManager/templates/sites-list/site-fields.html @@ -82,6 +82,13 @@ {{ 'SitesManager_AliasUrlHelp' | translate }} </div> <div sites-manager-multiline-field field="site.alias_urls" cols="25" rows="3"></div> + + <div class="form-help"> + {{ 'SitesManager_OnlyMatchedUrlsAllowedHelp' | translate }} + </div> + <label class="checkbox"> + <input type="checkbox" ng-model="site.exclude_unknown_urls" ng-true-value="1" ng-false-value="0"> {{ 'SitesManager_OnlyMatchedUrlsAllowed' | translate:'':'' }} + </label> </div> <div class="form-group"> diff --git a/plugins/SitesManager/tests/Integration/ApiTest.php b/plugins/SitesManager/tests/Integration/ApiTest.php index 0bb70872bba5e03c3f3fbb9cb1b0dede792fa9f8..76de4ba10f399d1ffcc55a2bc4ffbb98f172f9a4 100644 --- a/plugins/SitesManager/tests/Integration/ApiTest.php +++ b/plugins/SitesManager/tests/Integration/ApiTest.php @@ -43,15 +43,11 @@ class ApiTest extends IntegrationTestCase /** * empty name -> exception + * @expectedException \Exception */ - public function testAddSiteEmptyName() + public function test_addSite_WithEmptyName_ThrowsException() { - try { - API::getInstance()->addSite("", array("http://piwik.net")); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + API::getInstance()->addSite("", array("http://piwik.net")); } /** @@ -72,21 +68,17 @@ class ApiTest extends IntegrationTestCase * wrong urls -> exception * * @dataProvider getInvalidUrlData + * @expectedException \Exception */ - public function testAddSiteWrongUrls($url) + public function test_addSite_WithWrongUrls_ThrowsException($url) { - try { - API::getInstance()->addSite("name", $url); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + API::getInstance()->addSite("name", $url); } /** * Test with valid IPs */ - public function testAddSiteExcludedIpsAndtimezoneAndCurrencyAndExcludedQueryParametersValid() + public function test_addSite_WithExcludedIps_AndTimezone_AndCurrency_AndExcludedQueryParameters_SucceedsWhenParamsAreValid() { $ips = '1.2.3.4,1.1.1.*,1.2.*.*,1.*.*.*'; $timezone = 'Europe/Paris'; @@ -138,22 +130,18 @@ class ApiTest extends IntegrationTestCase * Test with invalid IPs * * @dataProvider getInvalidIPsData + * @expectedException \Exception */ - public function testAddSiteExcludedIpsNotValid($ip) + public function test_addSite_WithInvalidExcludedIps_ThrowsException($ip) { - try { - API::getInstance()->addSite("name", "http://piwik.net/", $ecommerce = 0, - $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, $ip); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + API::getInstance()->addSite("name", "http://piwik.net/", $ecommerce = 0, + $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, $ip); } /** * one url -> one main_url and nothing inserted as alias urls */ - public function testAddSiteOneUrl() + public function test_addSite_WithOneUrl_Succeeds_AndCreatesNoAliasUrls() { $url = "http://piwik.net/"; $urlOK = "http://piwik.net"; @@ -171,7 +159,7 @@ class ApiTest extends IntegrationTestCase /** * several urls -> one main_url and others as alias urls */ - public function testAddSiteSeveralUrls() + public function test_addSite_WithSeveralUrls_Succeeds_AndCreatesAliasUrls() { $urls = array("http://piwik.net/", "http://piwik.com", "https://piwik.net/test/"); $urlsOK = array("http://piwik.net", "http://piwik.com", "https://piwik.net/test"); @@ -188,7 +176,7 @@ class ApiTest extends IntegrationTestCase /** * strange name */ - public function testAddSiteStrangeName() + public function test_addSite_WithStrangeName_Succeeds() { $name = "supertest(); ~@@()''!£\$'%%^'!£ போ"; $idsite = API::getInstance()->addSite($name, "http://piwik.net"); @@ -203,7 +191,7 @@ class ApiTest extends IntegrationTestCase * @expectedException \Exception * @expectedExceptionMessage Only 100 characters are allowed */ - public function testAddSite_ShouldFailAndNotCreatedASiteIfASettingIsInvalid() + public function test_addSite_ShouldFailAndNotCreatedASite_IfASettingIsInvalid() { try { $type = MobileAppMeasurable\Type::ID; @@ -219,7 +207,7 @@ class ApiTest extends IntegrationTestCase } } - public function testAddSite_ShouldSavePassedMeasurableSettings_IfSettingsAreValid() + public function test_addSite_ShouldSavePassedMeasurableSettings_IfSettingsAreValid() { $type = MobileAppMeasurable\Type::ID; $settings = array('app_id' => 'org.piwik.mobile2'); @@ -292,7 +280,7 @@ class ApiTest extends IntegrationTestCase /** * no duplicate -> all the urls are saved */ - public function testAddSiteUrlsnoDuplicate() + public function test_addSiteAliasUrls_WithUniqueUrls_SavesAllUrls() { $idsite = $this->_addSite(); @@ -330,7 +318,7 @@ class ApiTest extends IntegrationTestCase /** * duplicate -> don't save the already existing URLs */ - public function testAddSiteUrlsDuplicate() + public function test_addSiteAliasUrls_WithDuplicateUrls_RemovesDuplicatesBeforeSaving() { $idsite = $this->_addSite(); @@ -354,7 +342,7 @@ class ApiTest extends IntegrationTestCase /** * case empty array => nothing happens */ - public function testAddSiteUrlsNoUrlsToAdd1() + public function test_addSiteAliasUrls_WithNoUrls_DoesNothing() { $idsite = $this->_addSite(); @@ -378,7 +366,7 @@ class ApiTest extends IntegrationTestCase /** * case array only duplicate => nothing happens */ - public function testAddSiteUrlsNoUrlsToAdd2() + public function test_addSiteAliasUrls_WithAlreadyPersistedUrls_DoesNothing() { $idsite = $this->_addSite(); @@ -401,51 +389,50 @@ class ApiTest extends IntegrationTestCase /** * wrong format urls => exception + * @expectedException \Exception */ - public function testAddSiteUrlsWrongUrlsFormat3() + public function test_addSiteAliasUrls_WithIncorrectFormat_ThrowsException_3() { - try { - $idsite = $this->_addSite(); - $toAdd = array("http:mpigeq"); - API::getInstance()->addSiteAliasUrls($idsite, $toAdd); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + $idsite = $this->_addSite(); + $toAdd = array("http:mpigeq"); + API::getInstance()->addSiteAliasUrls($idsite, $toAdd); } /** * wrong idsite => no exception because simply no access to this resource + * @expectedException \Exception */ - public function testAddSiteUrlsWrongIdSite1() + public function test_addSiteAliasUrls_WithWrongIdSite_ThrowsException() { - try { - $toAdd = array("http://pigeq.com/test"); - API::getInstance()->addSiteAliasUrls(-1, $toAdd); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + $toAdd = array("http://pigeq.com/test"); + API::getInstance()->addSiteAliasUrls(-1, $toAdd); } /** * wrong idsite => exception + * @expectedException \Exception */ - public function testAddSiteUrlsWrongIdSite2() + public function test_addSiteAliasUrls_WithWrongIdSite_ThrowsException2() { - try { - $toAdd = array("http://pigeq.com/test"); - API::getInstance()->addSiteAliasUrls(155, $toAdd); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + $toAdd = array("http://pigeq.com/test"); + API::getInstance()->addSiteAliasUrls(155, $toAdd); + } + + public function test_addSite_CorrectlySavesExcludeUnknownUrlsSetting() + { + $idSite = API::getInstance()->addSite("site", array("http://piwik.net"), $ecommerce = null, $siteSearch = null, + $searchKeywordParams = null, $searchCategoryParams = null, $excludedIps = null, $excludedQueryParams = null, + $timezone = null, $currency = null, $group = null, $startDate = null, $excludedUserAgents = null, + $keepUrlFragments = null, $type = null, $settings = null, $excludeUnknownUrls = true); + + $site = API::getInstance()->getSiteFromId($idSite); + $this->assertEquals(1, $site['exclude_unknown_urls']); } /** * no Id -> empty array */ - public function testGetAllSitesIdNoId() + public function test_getAllSitesId_ReturnsNothing_WhenNoSitesSaved() { $ids = API::getInstance()->getAllSitesId(); $this->assertEquals(array(), $ids); @@ -454,7 +441,7 @@ class ApiTest extends IntegrationTestCase /** * several Id -> normal array */ - public function testGetAllSitesIdSeveralId() + public function test_getAllSitesId_ReturnsAllIds_WhenMultipleSitesPersisted() { $name = "tetq"; $idsites = array( @@ -471,34 +458,27 @@ class ApiTest extends IntegrationTestCase /** * wrong id => exception + * @expectedException \Exception */ - public function testGetSiteFromIdWrongId1() + public function test_getSiteFromId_WithWrongId_ThrowsException1() { - try { - API::getInstance()->getSiteFromId(0); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + API::getInstance()->getSiteFromId(0); } /** * wrong id => exception + * @expectedException \Exception */ - public function testGetSiteFromIdWrongId2() + public function test_getSiteFromId_WithWrongId_ThrowsException2() { - try { - API::getInstance()->getSiteFromId("x1"); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + API::getInstance()->getSiteFromId("x1"); } /** * wrong id : no access => exception + * @expectedException \Exception */ - public function testGetSiteFromIdWrongId3() + public function test_getSiteFromId_ThrowsException_WhenTheUserDoesNotHavaAcessToTheSite() { $idsite = API::getInstance()->addSite("site", array("http://piwik.net", "http://piwik.com/test/")); $this->assertEquals(1, $idsite); @@ -507,18 +487,13 @@ class ApiTest extends IntegrationTestCase FakeAccess::setIdSitesView(array(2)); FakeAccess::setIdSitesAdmin(array()); - try { - API::getInstance()->getSiteFromId(1); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + API::getInstance()->getSiteFromId(1); } /** * normal case */ - public function testGetSiteFromIdNormalId() + public function test_getSiteFromId_WithNormalId_ReturnsTheCorrectSite() { $name = "website ''"; $idsite = API::getInstance()->addSite($name, array("http://piwik.net", "http://piwik.com/test/")); @@ -532,7 +507,7 @@ class ApiTest extends IntegrationTestCase /** * there is no admin site available -> array() */ - public function testGetSitesWithAdminAccessNoResult() + public function test_getSitesWithAdminAccess_ReturnsNothing_WhenUserHasNoAdminAccess() { FakeAccess::setIdSitesAdmin(array()); @@ -543,15 +518,15 @@ class ApiTest extends IntegrationTestCase /** * normal case, admin and view and noaccess website => return only admin */ - public function testGetSitesWithAdminAccess_shouldOnlyReturnSitesHavingActuallyAdminAccess() + public function test_getSitesWithAdminAccess_shouldOnlyReturnSitesHavingActuallyAdminAccess() { API::getInstance()->addSite("site1", array("http://piwik.net", "http://piwik.com/test/")); API::getInstance()->addSite("site2", array("http://piwik.com/test/")); 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' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => '', 'keep_url_fragment' => 0, 'type' => 'website'), - 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' => '', 'keep_url_fragment' => 0, 'type' => 'website'), + 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' => '', 'keep_url_fragment' => 0, 'type' => 'website', 'exclude_unknown_urls' => 0), + 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' => '', 'keep_url_fragment' => 0, 'type' => 'website', 'exclude_unknown_urls' => 0), ); FakeAccess::setIdSitesAdmin(array(1, 3)); @@ -564,7 +539,7 @@ class ApiTest extends IntegrationTestCase $this->assertEquals($resultWanted, $sites); } - public function testGetSitesWithAdminAccess_shouldApplyLimit_IfSet() + public function test_getSitesWithAdminAccess_shouldApplyLimit_IfSet() { $this->createManySitesWithAdminAccess(40); @@ -581,7 +556,7 @@ class ApiTest extends IntegrationTestCase $this->assertReturnedSitesContainsSiteIds(range(1, 10), $sites); } - public function testGetSitesWithAdminAccess_shouldApplyPattern_IfSetAndFindBySiteName() + public function test_getSitesWithAdminAccess_shouldApplyPattern_IfSetAndFindBySiteName() { $this->createManySitesWithAdminAccess(40); @@ -590,7 +565,7 @@ class ApiTest extends IntegrationTestCase $this->assertReturnedSitesContainsSiteIds(array(38), $sites); } - public function testGetSitesWithAdminAccess_shouldApplyPattern_IfSetAndFindByUrl() + public function test_getSitesWithAdminAccess_shouldApplyPattern_IfSetAndFindByUrl() { $this->createManySitesWithAdminAccess(40); @@ -598,7 +573,7 @@ class ApiTest extends IntegrationTestCase $this->assertReturnedSitesContainsSiteIds(array(38), $sites); } - public function testGetSitesWithAdminAccess_shouldApplyPattern_AndFindMany() + public function test_getSitesWithAdminAccess_shouldApplyPattern_AndFindMany() { $this->createManySitesWithAdminAccess(40); @@ -606,7 +581,7 @@ class ApiTest extends IntegrationTestCase $this->assertReturnedSitesContainsSiteIds(array(5, 15, 25, 35), $sites); } - public function testGetSitesWithAdminAccess_shouldApplyPatternAndLimit() + public function test_getSitesWithAdminAccess_shouldApplyPatternAndLimit() { $this->createManySitesWithAdminAccess(40); @@ -640,7 +615,7 @@ class ApiTest extends IntegrationTestCase /** * there is no admin site available -> array() */ - public function testGetSitesWithViewAccessNoResult() + public function test_getSitesWithViewAccess_ReturnsNothing_IfUserHasNoViewOrAdminAccess() { FakeAccess::setIdSitesView(array()); FakeAccess::setIdSitesAdmin(array()); @@ -652,15 +627,15 @@ class ApiTest extends IntegrationTestCase /** * normal case, admin and view and noaccess website => return only admin */ - public function testGetSitesWithViewAccess() + public function test_getSitesWithViewAccess_ReturnsSitesWithViewAccess() { API::getInstance()->addSite("site1", array("http://piwik.net", "http://piwik.com/test/")); API::getInstance()->addSite("site2", array("http://piwik.com/test/")); 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' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => '', 'keep_url_fragment' => 0, 'type' => 'website'), - 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' => '', 'keep_url_fragment' => 0, 'type' => 'website'), + 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' => '', 'keep_url_fragment' => 0, 'type' => 'website', 'exclude_unknown_urls' => 0), + 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' => '', 'keep_url_fragment' => 0, 'type' => 'website', 'exclude_unknown_urls' => 0), ); FakeAccess::setIdSitesView(array(1, 3)); @@ -676,7 +651,7 @@ class ApiTest extends IntegrationTestCase /** * there is no admin site available -> array() */ - public function testGetSitesWithAtLeastViewAccessNoResult() + public function test_getSitesWithAtLeastViewAccess_ReturnsNothing_WhenUserHasNoAccess() { FakeAccess::setIdSitesView(array()); FakeAccess::setIdSitesAdmin(array()); @@ -688,15 +663,15 @@ class ApiTest extends IntegrationTestCase /** * normal case, admin and view and noaccess website => return only admin */ - public function testGetSitesWithAtLeastViewAccess() + public function test_getSitesWithAtLeastViewAccess_ReturnsSitesWithViewAccess() { API::getInstance()->addSite("site1", array("http://piwik.net", "http://piwik.com/test/"), $ecommerce = 1); API::getInstance()->addSite("site2", array("http://piwik.com/test/")); 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' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => '', 'keep_url_fragment' => 0, 'type' => 'website'), - 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' => '', 'keep_url_fragment' => 0, 'type' => 'website'), + 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' => '', 'keep_url_fragment' => 0, 'type' => 'website', 'exclude_unknown_urls' => 0), + 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' => '', 'keep_url_fragment' => 0, 'type' => 'website', 'exclude_unknown_urls' => 0), ); FakeAccess::setIdSitesView(array(1, 3)); @@ -712,7 +687,7 @@ class ApiTest extends IntegrationTestCase /** * no urls for this site => array() */ - public function testGetSiteUrlsFromIdNoUrls() + public function test_getSiteUrlsFromId_ReturnsMainUrlOnly_WhenNoAliasUrls() { $idsite = API::getInstance()->addSite("site1", array("http://piwik.net")); @@ -723,7 +698,7 @@ class ApiTest extends IntegrationTestCase /** * normal case */ - public function testGetSiteUrlsFromIdManyUrls() + public function test_getSiteUrlsFromId_ReturnsMainAndAliasUrls() { $site = array("http://piwik.net", "http://piwik.org", @@ -744,23 +719,19 @@ class ApiTest extends IntegrationTestCase /** * wrongId => exception + * @expectedException \Exception */ - public function testGetSiteUrlsFromIdWrongId() + public function test_getSiteUrlsFromId_ThrowsException_WhenSiteIdIsIncorrect() { - try { - FakeAccess::setIdSitesView(array(3)); - FakeAccess::setIdSitesAdmin(array()); - API::getInstance()->getSiteUrlsFromId(1); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + FakeAccess::setIdSitesView(array(3)); + FakeAccess::setIdSitesAdmin(array()); + API::getInstance()->getSiteUrlsFromId(1); } /** * one url => no change to alias urls */ - public function testUpdateSiteOneUrl() + public function test_updateSite_WithOneUrl_RemovesAliasUrls_AndUpdatesTheSiteCorrectly() { $urls = array("http://piwiknew.com", "http://piwiknew.net", @@ -808,7 +779,7 @@ class ApiTest extends IntegrationTestCase /** * strange name and NO URL => name ok, main_url not updated */ - public function testUpdateSiteStrangeNameNoUrl() + public function test_updateSite_WithStrangeName_AndNoAliasUrls_UpdatesTheName_ButNoUrls() { $idsite = API::getInstance()->addSite("site1", "http://main.url"); $newName = "test toto@{'786'}"; @@ -826,7 +797,7 @@ class ApiTest extends IntegrationTestCase * several urls => both main and alias are updated * also test the update of group field */ - public function testUpdateSiteSeveralUrlsAndGroup() + public function test_updateSite_WithSeveralUrlsAndGroup_UpdatesGroupAndUrls() { $urls = array("http://piwiknew.com", "http://piwiknew.net", @@ -875,7 +846,7 @@ class ApiTest extends IntegrationTestCase * @expectedException \Exception * @expectedExceptionMessage Only 100 characters are allowed */ - public function testUpdateSite_ShouldFailAndNotUpdateSiteIfASettingIsInvalid() + public function test_updateSite_ShouldFailAndNotUpdateSite_IfASettingIsInvalid() { $type = MobileAppMeasurable\Type::ID; $idSite = $this->addSiteWithType($type, array()); @@ -892,7 +863,7 @@ class ApiTest extends IntegrationTestCase } } - public function testUpdateSite_ShouldSavePassedMeasurableSettings_IfSettingsAreValid() + public function test_updateSite_ShouldSavePassedMeasurableSettings_IfSettingsAreValid() { $type = MobileAppMeasurable\Type::ID; $idSite = $this->addSiteWithType($type, array()); @@ -907,6 +878,22 @@ class ApiTest extends IntegrationTestCase $this->assertSame('org.piwik.mobile2', $measurable->getSettingValue('app_id')); } + public function test_updateSite_CorreclySavesExcludedUnknownUrlSettings() + { + $idSite = API::getInstance()->addSite("site1", array("http://piwik.net")); + + $site = API::getInstance()->getSiteFromId($idSite); + $this->assertEquals(0, $site['exclude_unknown_urls']); + + API::getInstance()->updateSite($idSite, $siteName = null, $urls = null, $ecommerce = null, $siteSearch = null, + $searchKeywordParams = null, $searchCategoryParams = null, $excludedIps = null, $excludedQueryParameters = null, + $timzeone = null, $currency = null, $group = null, $startDate = null, $excludedUserAgents = null, + $keepUrlFragments = null, $type = null, $settings = null, $excludeUnknownUrls = true); + + $site = API::getInstance()->getSiteFromId($idSite); + $this->assertEquals(1, $site['exclude_unknown_urls']); + } + /** * @expectedException Exception * @expectedExceptionMessage SitesManager_ExceptionDeleteSite @@ -1005,31 +992,25 @@ class ApiTest extends IntegrationTestCase /** * * @dataProvider getInvalidTimezoneData + * @expectedException \Exception */ - public function testAddSitesInvalidTimezone($timezone) + public function test_addSite_WithInvalidTimezone_ThrowsException($timezone) { - try { - API::getInstance()->addSite("site1", array('http://example.org'), $ecommerce = 0, - $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, $ip = '', $params = '', $timezone); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + API::getInstance()->addSite("site1", array('http://example.org'), $ecommerce = 0, + $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, $ip = '', $params = '', $timezone); } - public function testAddSitesInvalidCurrency() + /** + * @expectedException \Exception + */ + public function test_addSite_WithInvalidCurrency_ThrowsException() { - try { - $invalidCurrency = '€'; - API::getInstance()->addSite("site1", array('http://example.org'), $ecommerce = 0, - $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, '', 'UTC', $invalidCurrency); - } catch (Exception $e) { - return; - } - $this->fail('Expected exception not raised'); + $invalidCurrency = '€'; + API::getInstance()->addSite("site1", array('http://example.org'), $ecommerce = 0, + $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, '', 'UTC', $invalidCurrency); } - public function testSetDefaultTimezoneAndCurrencyAndExcludedQueryParametersAndExcludedIps() + public function test_setDefaultTimezone_AndCurrency_AndExcludedQueryParameters_AndExcludedIps_UpdatesDefaultsCorreclty() { // test that they return default values $defaultTimezone = API::getInstance()->getDefaultTimezone(); @@ -1095,7 +1076,7 @@ class ApiTest extends IntegrationTestCase $this->assertFalse(Site::isEcommerceEnabledFor($idsite)); } - public function testGetSitesIdFromSiteUrl_asSuperUser() + public function test_getSitesIdFromSiteUrl_AsSuperUser_ReturnsTheRequestedSiteIds() { API::getInstance()->addSite("site1", array("http://piwik.net", "http://piwik.com")); API::getInstance()->addSite("site2", array("http://piwik.com", "http://piwik.net")); @@ -1114,14 +1095,14 @@ class ApiTest extends IntegrationTestCase $this->assertTrue(count($idsites) == 3); } - public function test_getSitesIdFromSiteUrl_matchesBothHttpAndHttpsUrls_asSuperUser() + public function test_getSitesIdFromSiteUrl_MatchesBothHttpAndHttpsUrls_AsSuperUser() { API::getInstance()->addSite("site1", array("https://piwik.org", "http://example.com", "fb://special-url")); $this->assert_getSitesIdFromSiteUrl_matchesBothHttpAndHttpsUrls(); } - public function test_getSitesIdFromSiteUrl_matchesBothHttpAndHttpsUrls_asUserWithViewPermission() + public function test_getSitesIdFromSiteUrl_MatchesBothHttpAndHttpsUrls_AsUserWithViewPermission() { API::getInstance()->addSite("site1", array("https://piwik.org", "http://example.com", "fb://special-url")); @@ -1163,7 +1144,7 @@ class ApiTest extends IntegrationTestCase $this->assertTrue(count($idsites) == 0); } - public function test_getSitesIdFromSiteUrl_asUser() + public function test_getSitesIdFromSiteUrl_AsUser() { API::getInstance()->addSite("site1", array("http://www.piwik.net", "https://piwik.com")); API::getInstance()->addSite("site2", array("http://piwik.com", "http://piwik.net")); @@ -1215,7 +1196,7 @@ class ApiTest extends IntegrationTestCase $this->assertEquals(3, count($idsites)); } - public function testGetSitesFromTimezones() + public function test_getSitesFromTimezones_ReturnsCorrectIdSites() { API::getInstance()->addSite("site3", array("http://piwik.org"), null, $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, null, null, 'UTC'); $idsite2 = API::getInstance()->addSite("site3", array("http://piwik.org"), null, $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, null, null, 'Pacific/Auckland'); diff --git a/plugins/SitesManager/tests/System/expected/test_SitesManager__SitesManager.getPatternMatchSites.xml b/plugins/SitesManager/tests/System/expected/test_SitesManager__SitesManager.getPatternMatchSites.xml index 1fa55da06a40476a35c173de440b50fff85fbd79..baea44a4a8c87205ae766a9ceef4e3dab64e9a8b 100644 --- a/plugins/SitesManager/tests/System/expected/test_SitesManager__SitesManager.getPatternMatchSites.xml +++ b/plugins/SitesManager/tests/System/expected/test_SitesManager__SitesManager.getPatternMatchSites.xml @@ -11,6 +11,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -29,6 +30,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -47,6 +49,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -65,6 +68,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -83,6 +87,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -101,6 +106,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -119,6 +125,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -137,6 +144,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -155,6 +163,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -173,6 +182,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -191,6 +201,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> diff --git a/plugins/SitesManager/tests/System/expected/test_SitesManagerwithLimit__SitesManager.getPatternMatchSites.xml b/plugins/SitesManager/tests/System/expected/test_SitesManagerwithLimit__SitesManager.getPatternMatchSites.xml index 19de3478312c480d7a2d16295bcdc73c004bd466..31601184b7794d21647204b44fa6a92da3511979 100644 --- a/plugins/SitesManager/tests/System/expected/test_SitesManagerwithLimit__SitesManager.getPatternMatchSites.xml +++ b/plugins/SitesManager/tests/System/expected/test_SitesManagerwithLimit__SitesManager.getPatternMatchSites.xml @@ -11,6 +11,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> @@ -29,6 +30,7 @@ <sitesearch_category_parameters /> <timezone>UTC</timezone> <currency>USD</currency> + <exclude_unknown_urls>0</exclude_unknown_urls> <excluded_ips /> <excluded_parameters /> <excluded_user_agents /> diff --git a/tests/PHPUnit/Fixtures/InvalidVisits.php b/tests/PHPUnit/Fixtures/InvalidVisits.php index ef7ece2803f7be4607f6a85058f7ffceffae377c..5518a7a163f3689f0d595f1346fdbb4d27221588 100644 --- a/tests/PHPUnit/Fixtures/InvalidVisits.php +++ b/tests/PHPUnit/Fixtures/InvalidVisits.php @@ -97,6 +97,21 @@ class InvalidVisits extends Fixture self::checkResponse($t->doTrackPageView('visit from IP globally excluded')); } + // test unknown url exclusion works + $urls = array("http://piwik.net", "http://my.stuff.com/"); + API::getInstance()->updateSite($idSite, $siteName = null, $urls, $ecommerce = null, $siteSearch = null, + $searchKeywordParameters = null, $searchCategoryParameters = null, $excludedIps = null, $excludedQueryParams = null, + $timezone = null, $currency = null, $group = null, $startDate = null, $excludedUserAgents = null, + $keepUrlFragments = null, $type = null, $settings = null, $excludeUnknownUrls = 1); + + $t->setIp("125.4.5.6"); + + $t->setUrl("http://piwik.com/to/the/moon"); + $t->doTrackPageView("ignored, not from piwik.net"); + + $t->setUrl("http://their.stuff.com/back/to/the/future"); + $t->doTrackPageView("ignored, not from my.stuff.com"); + try { @$t->setAttributionInfo(array()); self::fail(); diff --git a/tests/PHPUnit/Integration/Tracker/VisitTest.php b/tests/PHPUnit/Integration/Tracker/VisitTest.php index 78410327c556388e21bd469466f19c635f6d3a99..e870fa6c51c01532d3b4200dea3ec87b0761ec4d 100644 --- a/tests/PHPUnit/Integration/Tracker/VisitTest.php +++ b/tests/PHPUnit/Integration/Tracker/VisitTest.php @@ -99,6 +99,53 @@ class VisitTest extends IntegrationTestCase } } + public function getExcludeByUrlData() + { + return array( + array(array('http://test.com'), true, array( + 'http://test.com' => true, + 'https://test.com' => true, + 'http://test.com/uri' => true, + 'http://test.com/?query' => true, + 'http://xtest.com' => false, + )), + array(array('http://test.com', 'http://localhost'), true, array( + 'http://test.com' => true, + 'http://localhost' => true, + 'http://x.com' => false, + )), + array(array('http://test.com'), false, array( + 'http://x.com' => true, + )), + array(array('http://test.com', 'http://sub.test2.com'), true, array( + 'http://sub.test.com' => true, + 'http://sub.sub.test.com' => true, + 'http://subtest.com' => false, + 'http://test.com.org' => false, + 'http://sub.test2.com' => true, + 'http://x.sub.test2.com' => true, + 'http://xsub.test2.com' => false, + 'http://sub.test2.com.org' => false, + )), + ); + } + + /** + * @dataProvider getExcludeByUrlData + */ + public function testExcludeByUrl($siteUrls, $excludeUnknownUrls, array $urlsTracked) + { + $siteId = API::getInstance()->addSite('name', $siteUrls, $ecommerce = null, $siteSearch = null, $searchKeywordParameters = null, $searchCategoryParameters = null, null, null, null, null, null, null, null, null, null, null, $excludeUnknownUrls); + foreach ($urlsTracked as $url => $isTracked) { + $visitExclude = new VisitExcluded(new Request(array( + 'idsite' => $siteId, + 'rec' => 1, + 'url' => $url + ))); + $this->assertEquals($isTracked, !$visitExclude->isExcluded()); + } + } + /** * @dataProvider getChromeDataSaverData */