diff options
author | Thomas Steur <tsteur@users.noreply.github.com> | 2018-12-06 08:44:01 +0300 |
---|---|---|
committer | diosmosis <diosmosis@users.noreply.github.com> | 2018-12-06 08:44:01 +0300 |
commit | 7b6a14626960795b0acdf4a064cd3982d7704f2b (patch) | |
tree | 1f8b5fc7d7869c77e91a1f8dc2ab592b3f8de4ca /plugins | |
parent | 1fe8a6ee582c2f61dc209b7df856695378007c23 (diff) |
Report tracking into wrong Site ID and missing token auth (#13493)
* log tracking failures
* added page
* tweak UI
* use a db column instead of option table to simplify code
* add system summary, notifiy super users by email, fixes, update, ...
* more fixes, needs tests next
* add widget for tracking failures
* ensure to not log any failure when visit is excluded
* some tests and fixes
* added tests
* added missing test
* apply review feedback
* fix tests
* trying to fix test
* fix tests
* fix update names
* fix tests
* Fix another test.
Diffstat (limited to 'plugins')
40 files changed, 1062 insertions, 16 deletions
diff --git a/plugins/BulkTracking/tests/Integration/RequestsTest.php b/plugins/BulkTracking/tests/Integration/RequestsTest.php index 7f6236d82c..e0832770d7 100644 --- a/plugins/BulkTracking/tests/Integration/RequestsTest.php +++ b/plugins/BulkTracking/tests/Integration/RequestsTest.php @@ -33,6 +33,8 @@ class RequestsTest extends IntegrationTestCase { parent::setUp(); + Fixture::createWebsite('2014-01-02 03:04:05'); + $this->requests = new Requests(); } diff --git a/plugins/CoreAdminHome/.gitignore b/plugins/CoreAdminHome/.gitignore new file mode 100644 index 0000000000..c8c9480010 --- /dev/null +++ b/plugins/CoreAdminHome/.gitignore @@ -0,0 +1 @@ +tests/System/processed/*xml
\ No newline at end of file diff --git a/plugins/CoreAdminHome/API.php b/plugins/CoreAdminHome/API.php index 6fc3313696..19eef3d946 100644 --- a/plugins/CoreAdminHome/API.php +++ b/plugins/CoreAdminHome/API.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\CoreAdminHome; use Exception; use Monolog\Handler\StreamHandler; use Monolog\Logger; +use Piwik\Access; use Piwik\ArchiveProcessor\Rules; use Piwik\Config; use Piwik\Container\StaticContainer; @@ -22,6 +23,7 @@ use Piwik\Piwik; use Piwik\Segment; use Piwik\Scheduler\Scheduler; use Piwik\Site; +use Piwik\Tracker\Failures; use Piwik\Url; /** @@ -39,10 +41,16 @@ class API extends \Piwik\Plugin\API */ private $invalidator; - public function __construct(Scheduler $scheduler, ArchiveInvalidator $invalidator) + /** + * @var Failures + */ + private $trackingFailures; + + public function __construct(Scheduler $scheduler, ArchiveInvalidator $invalidator, Failures $trackingFailures) { $this->scheduler = $scheduler; $this->invalidator = $invalidator; + $this->trackingFailures = $trackingFailures; } /** @@ -180,6 +188,55 @@ class API extends \Piwik\Plugin\API } /** + * Deletes all tracking failures this user has at least admin access to. + * A super user will also delete tracking failures for sites that don't exist. + */ + public function deleteAllTrackingFailures() + { + if (Piwik::hasUserSuperUserAccess()) { + $this->trackingFailures->deleteAllTrackingFailures(); + } else { + Piwik::checkUserHasSomeAdminAccess(); + $idSites = Access::getInstance()->getSitesIdWithAdminAccess(); + Piwik::checkUserHasAdminAccess($idSites); + $this->trackingFailures->deleteTrackingFailures($idSites); + } + } + + /** + * Deletes a specific tracking failure + * @param int $idSite + * @param int $idFailure + */ + public function deleteTrackingFailure($idSite, $idFailure) + { + $idSite = (int) $idSite; + Piwik::checkUserHasAdminAccess($idSite); + + $this->trackingFailures->deleteTrackingFailure($idSite, $idFailure); + } + + /** + * Get all tracking failures. A user retrieves only tracking failures for sites with at least admin access. + * A super user will also retrieve failed requests for sites that don't exist. + * @return array + */ + public function getTrackingFailures() + { + if (Piwik::hasUserSuperUserAccess()) { + $failures = $this->trackingFailures->getAllFailures(); + } else { + Piwik::checkUserHasSomeAdminAccess(); + $idSites = Access::getInstance()->getSitesIdWithAdminAccess(); + Piwik::checkUserHasAdminAccess($idSites); + + $failures = $this->trackingFailures->getFailuresForSites($idSites); + } + + return $failures; + } + + /** * Ensure the specified dates are valid. * Store invalid date so we can log them * @param array $dates diff --git a/plugins/CoreAdminHome/Controller.php b/plugins/CoreAdminHome/Controller.php index bee4b57cac..32441e0d39 100644 --- a/plugins/CoreAdminHome/Controller.php +++ b/plugins/CoreAdminHome/Controller.php @@ -60,6 +60,7 @@ class Controller extends ControllerAdmin $hasPremiumFeatures = $widgetsList->isDefined('Marketplace', 'getPremiumFeatures'); $hasNewPlugins = $widgetsList->isDefined('Marketplace', 'getNewPlugins'); $hasDiagnostics = $widgetsList->isDefined('Installation', 'getSystemCheck'); + $hasTrackingFailures = $widgetsList->isDefined('CoreAdminHome', 'getTrackingFailures'); return $this->renderTemplate('home', array( 'isInternetEnabled' => $isInternetEnabled, @@ -70,6 +71,7 @@ class Controller extends ControllerAdmin 'hasDonateForm' => $hasDonateForm, 'hasPiwikBlog' => $hasPiwikBlog, 'hasDiagnostics' => $hasDiagnostics, + 'hasTrackingFailures' => $hasTrackingFailures, )); } @@ -79,6 +81,13 @@ class Controller extends ControllerAdmin return; } + public function trackingFailures() + { + Piwik::checkUserHasSomeAdminAccess(); + + return $this->renderTemplate('trackingFailures'); + } + public function generalSettings() { Piwik::checkUserHasSuperUserAccess(); diff --git a/plugins/CoreAdminHome/CoreAdminHome.php b/plugins/CoreAdminHome/CoreAdminHome.php index a87c6da948..3e0d0e4912 100644 --- a/plugins/CoreAdminHome/CoreAdminHome.php +++ b/plugins/CoreAdminHome/CoreAdminHome.php @@ -8,10 +8,10 @@ */ namespace Piwik\Plugins\CoreAdminHome; -use Piwik\Db; +use Piwik\API\Request; use Piwik\Piwik; use Piwik\ProxyHttp; -use Piwik\Settings\Plugin\UserSetting; +use Piwik\Plugins\CoreHome\SystemSummary; use Piwik\Settings\Storage\Backend\PluginSettingsTable; /** @@ -20,7 +20,7 @@ use Piwik\Settings\Storage\Backend\PluginSettingsTable; class CoreAdminHome extends \Piwik\Plugin { /** - * @see Piwik\Plugin::registerEvents + * @see \Piwik\Plugin::registerEvents */ public function registerEvents() { @@ -30,10 +30,24 @@ class CoreAdminHome extends \Piwik\Plugin 'UsersManager.deleteUser' => 'cleanupUser', 'API.DocumentationGenerator.@hideExceptForSuperUser' => 'displayOnlyForSuperUser', 'Template.jsGlobalVariables' => 'addJsGlobalVariables', - 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys' + 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', + 'System.addSystemSummaryItems' => 'addSystemSummaryItems', ); } + public function addSystemSummaryItems(&$systemSummary) + { + if (Piwik::isUserHasSomeAdminAccess()) { + $failures = Request::processRequest('CoreAdminHome.getTrackingFailures', [], []); + $numFailures = count($failures); + $icon = 'icon-error'; + if ($numFailures === 0) { + $icon = 'icon-ok'; + } + $systemSummary[] = new SystemSummary\Item($key = 'trackingfailures', Piwik::translate('CoreAdminHome_NTrackingFailures', $numFailures), $value = null, array('module' => 'CoreAdminHome', 'action' => 'trackingFailures'), $icon, $order = 9); + } + } + public function cleanupUser($userLogin) { PluginSettingsTable::removeAllUserSettingsForUser($userLogin); @@ -45,6 +59,7 @@ class CoreAdminHome extends \Piwik\Plugin $stylesheets[] = "plugins/Morpheus/stylesheets/base.less"; $stylesheets[] = "plugins/Morpheus/stylesheets/main.less"; $stylesheets[] = "plugins/CoreAdminHome/stylesheets/generalSettings.less"; + $stylesheets[] = "plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.less"; } public function getJsFiles(&$jsFiles) @@ -82,5 +97,23 @@ class CoreAdminHome extends \Piwik\Plugin $translationKeys[] = 'CoreAdminHome_ProtocolNotDetectedCorrectlySolution'; $translationKeys[] = 'CoreAdminHome_SettingsSaveSuccess'; $translationKeys[] = 'UserCountryMap_None'; + $translationKeys[] = 'Actions_ColumnPageURL'; + $translationKeys[] = 'General_Date'; + $translationKeys[] = 'General_Measurable'; + $translationKeys[] = 'General_Action'; + $translationKeys[] = 'General_Delete'; + $translationKeys[] = 'General_Id'; + $translationKeys[] = 'CoreHome_ClickToSeeFullInformation'; + $translationKeys[] = 'CoreAdminHome_LearnMore'; + $translationKeys[] = 'CoreAdminHome_ConfirmDeleteAllTrackingFailures'; + $translationKeys[] = 'CoreAdminHome_ConfirmDeleteThisTrackingFailure'; + $translationKeys[] = 'CoreAdminHome_DeleteAllFailures'; + $translationKeys[] = 'CoreAdminHome_NTrackingFailures'; + $translationKeys[] = 'CoreAdminHome_Problem'; + $translationKeys[] = 'CoreAdminHome_Solution'; + $translationKeys[] = 'CoreAdminHome_TrackingFailures'; + $translationKeys[] = 'CoreAdminHome_TrackingFailuresIntroduction'; + $translationKeys[] = 'CoreAdminHome_TrackingURL'; + $translationKeys[] = 'CoreAdminHome_NoKnownFailures'; } } diff --git a/plugins/CoreAdminHome/Emails/TrackingFailuresEmail.php b/plugins/CoreAdminHome/Emails/TrackingFailuresEmail.php new file mode 100644 index 0000000000..92d3ee2c16 --- /dev/null +++ b/plugins/CoreAdminHome/Emails/TrackingFailuresEmail.php @@ -0,0 +1,106 @@ +<?php +/** + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ + +namespace Piwik\Plugins\CoreAdminHome\Emails; + +use Piwik\Access; +use Piwik\Mail; +use Piwik\Piwik; +use Piwik\SettingsPiwik; +use Piwik\Url; +use Piwik\View; + +class TrackingFailuresEmail extends Mail +{ + /** + * @var string + */ + private $login; + + /** + * @var string + */ + private $emailAddress; + + /** + * @var int + */ + private $numFailures; + + public function __construct($login, $emailAddress, $numFailures) + { + parent::__construct(); + + $this->login = $login; + $this->emailAddress = $emailAddress; + $this->numFailures = (int)$numFailures; + + $this->setUpEmail(); + } + + /** + * @return string + */ + public function getLogin() + { + return $this->login; + } + + /** + * @return string + */ + public function getEmailAddress() + { + return $this->emailAddress; + } + + /** + * @return int + */ + public function getNumFailures() + { + return $this->numFailures; + } + + private function setUpEmail() + { + $this->setDefaultFromPiwik(); + $this->addTo($this->emailAddress); + $this->setSubject($this->getDefaultSubject()); + $this->setReplyTo($this->getFrom()); + $this->setWrappedHtmlBody($this->getDefaultBodyView()); + } + + private function getDefaultSubject() + { + return Piwik::translate('CoreAdminHome_TrackingFailuresEmailSubject'); + } + + private function getDefaultBodyView() + { + $view = new View('@CoreAdminHome/_trackingFailuresEmail.twig'); + $view->login = $this->login; + $view->emailAddress = $this->emailAddress; + $view->numFailures = $this->numFailures; + + $sitesId = Access::getInstance()->getSitesIdWithAtLeastViewAccess(); + $idSite = false; + if (!empty($sitesId)) { + $idSite = array_shift($sitesId); + } + $view->trackingFailuresUrl = SettingsPiwik::getPiwikUrl() . 'index.php?' . Url::getQueryStringFromParameters([ + 'module' => 'CoreAdminHome', + 'action' => 'trackingFailures', + 'period' => 'day', + 'date' => 'yesterday', + 'idSite' => $idSite + ]); + return $view; + } +}
\ No newline at end of file diff --git a/plugins/CoreAdminHome/Menu.php b/plugins/CoreAdminHome/Menu.php index 49a5579636..8ec288ec6c 100644 --- a/plugins/CoreAdminHome/Menu.php +++ b/plugins/CoreAdminHome/Menu.php @@ -36,6 +36,12 @@ class Menu extends \Piwik\Plugin\Menu $this->urlForAction('trackingCodeGenerator'), $order = 12); } + + if (Piwik::isUserHasSomeAdminAccess()) { + $menu->addDiagnosticItem('CoreAdminHome_TrackingFailures', + $this->urlForAction('trackingFailures'), + $order = 2); + } } public function configureTopMenu(MenuTop $menu) diff --git a/plugins/CoreAdminHome/Tasks.php b/plugins/CoreAdminHome/Tasks.php index 80560dde48..e6c7d1b242 100644 --- a/plugins/CoreAdminHome/Tasks.php +++ b/plugins/CoreAdminHome/Tasks.php @@ -18,13 +18,14 @@ use Piwik\Date; use Piwik\Db; use Piwik\Http; use Piwik\Option; +use Piwik\Piwik; use Piwik\Plugins\CoreAdminHome\Emails\JsTrackingCodeMissingEmail; +use Piwik\Plugins\CoreAdminHome\Emails\TrackingFailuresEmail; use Piwik\Plugins\CoreAdminHome\Tasks\ArchivesToPurgeDistributedList; use Piwik\Plugins\SitesManager\SitesManager; -use Piwik\Scheduler\Schedule\Daily; -use Piwik\Scheduler\Schedule\Monthly; use Piwik\Scheduler\Schedule\SpecificTime; use Piwik\Settings\Storage\Backend\MeasurableSettingsTable; +use Piwik\Tracker\Failures; use Piwik\Site; use Piwik\Tracker\Visit\ReferrerSpamFilter; use Psr\Log\LoggerInterface; @@ -43,10 +44,16 @@ class Tasks extends \Piwik\Plugin\Tasks */ private $logger; - public function __construct(ArchivePurger $archivePurger, LoggerInterface $logger) + /** + * @var Failures + */ + private $trackingFailures; + + public function __construct(ArchivePurger $archivePurger, LoggerInterface $logger, Failures $failures) { $this->archivePurger = $archivePurger; $this->logger = $logger; + $this->trackingFailures = $failures; } public function schedule() @@ -60,6 +67,9 @@ class Tasks extends \Piwik\Plugin\Tasks // lowest priority since tables should be optimized after they are modified $this->daily('optimizeArchiveTable', null, self::LOWEST_PRIORITY); + $this->daily('cleanupTrackingFailures', null, self::LOWEST_PRIORITY); + $this->weekly('notifyTrackingFailures', null, self::LOWEST_PRIORITY); + if(SettingsPiwik::isInternetEnabled() === true){ $this->weekly('updateSpammerBlacklist'); } @@ -140,6 +150,36 @@ class Tasks extends \Piwik\Plugin\Tasks } /** + * To test execute the following command: + * `./console core:run-scheduled-tasks "Piwik\Plugins\CoreAdminHome\Tasks.cleanupTrackingFailures"` + * + * @throws \Exception + */ + public function cleanupTrackingFailures() + { + // we remove possibly outdated/fixed tracking failures that have not occurred again recently + $this->trackingFailures->removeFailuresOlderThanDays(Failures::CLEANUP_OLD_FAILURES_DAYS); + } + + /** + * To test execute the following command: + * `./console core:run-scheduled-tasks "Piwik\Plugins\CoreAdminHome\Tasks.notifyTrackingFailures"` + * + * @throws \Exception + */ + public function notifyTrackingFailures() + { + $failures = $this->trackingFailures->getAllFailures(); + if (!empty($failures)) { + $superUsers = Piwik::getAllSuperUserAccessEmailAddresses(); + foreach ($superUsers as $login => $email) { + $email = new TrackingFailuresEmail($login, $email, count($failures)); + $email->send(); + } + } + } + + /** * @return bool `true` if the purge was executed, `false` if it was skipped. * @throws \Exception */ diff --git a/plugins/CoreAdminHome/Widgets/GetTrackingFailures.php b/plugins/CoreAdminHome/Widgets/GetTrackingFailures.php new file mode 100644 index 0000000000..c251c3c92f --- /dev/null +++ b/plugins/CoreAdminHome/Widgets/GetTrackingFailures.php @@ -0,0 +1,39 @@ +<?php +/** + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugins\CoreAdminHome\Widgets; + +use Piwik\API\Request; +use Piwik\Piwik; +use Piwik\Widget\Widget; +use Piwik\Widget\WidgetConfig; + +class GetTrackingFailures extends Widget +{ + public static function configure(WidgetConfig $config) + { + $config->setCategoryId('About Matomo'); + $config->setName('CoreAdminHome_TrackingFailures'); + $config->setOrder(5); + + if (!Piwik::isUserHasSomeAdminAccess()) { + $config->disable(); + } + } + + public function render() + { + Piwik::checkUserHasSomeAdminAccess(); + $failures = Request::processRequest('CoreAdminHome.getTrackingFailures'); + $numFailures = count($failures); + + return $this->renderTemplate('getTrackingFailures', array( + 'numFailures' => $numFailures + )); + } +}
\ No newline at end of file diff --git a/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.controller.js b/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.controller.js new file mode 100644 index 0000000000..e007fae6c3 --- /dev/null +++ b/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.controller.js @@ -0,0 +1,59 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').controller('TrackingFailuresController', TrackingFailuresController); + + TrackingFailuresController.$inject = ['piwikApi', 'piwik']; + + function TrackingFailuresController(piwikApi, piwik){ + var self = this; + this.failures = []; + this.sortColumn = 'idsite'; + this.sortReverse = false; + this.isLoading = false; + + this.changeSortOrder = function (columnToSort) { + if (this.sortColumn === columnToSort) { + this.sortReverse = !this.sortReverse; + } else { + this.sortColumn = columnToSort; + } + }; + + this.fetchAll = function () { + this.failures = []; + this.isLoading = true; + piwikApi.fetch({method: 'CoreAdminHome.getTrackingFailures', filter_limit: '-1'}).then(function (failures) { + self.failures = failures; + self.isLoading = false; + }, function () { + self.isLoading = false; + }); + }; + + this.deleteAll = function () { + piwik.helper.modalConfirm('#confirmDeleteAllTrackingFailures', {yes: function () { + self.failures = []; + piwikApi.fetch({method: 'CoreAdminHome.deleteAllTrackingFailures'}).then(function () { + self.fetchAll(); + }); + }}); + }; + + this.deleteFailure = function (idSite, idFailure) { + piwik.helper.modalConfirm('#confirmDeleteThisTrackingFailure', {yes: function () { + self.failures = []; + piwikApi.fetch({method: 'CoreAdminHome.deleteTrackingFailure', idSite: idSite, idFailure: idFailure}).then(function () { + self.fetchAll(); + }); + }}); + }; + + this.fetchAll(); + } + +})(); diff --git a/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.html b/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.html new file mode 100644 index 0000000000..07e4baa895 --- /dev/null +++ b/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.html @@ -0,0 +1,59 @@ +<div piwik-content-block + content-title="{{ 'CoreAdminHome_TrackingFailures'|translate }}" + class="matomoTrackingFailures"> + <p> + {{ 'CoreAdminHome_TrackingFailuresIntroduction'|translate:2 }} + <br /><br /> + <input class="btn deleteAllFailures" + ng-show="!trackingFailures.isLoading && trackingFailures.failures.length > 0" + type="button" ng-click="trackingFailures.deleteAll();" + value="{{'CoreAdminHome_DeleteAllFailures'|translate}}"> + </p> + + <div piwik-activity-indicator loading="trackingFailures.isLoading"></div> + + <table piwik-content-table> + <thead> + <tr> + <th ng-click="trackingFailures.changeSortOrder('idsite')">{{ 'General_Measurable'|translate }}</th> + <th ng-click="trackingFailures.changeSortOrder('problem')">{{ 'CoreAdminHome_Problem'|translate }}</th> + <th ng-click="trackingFailures.changeSortOrder('solution')">{{ 'CoreAdminHome_Solution'|translate }}</th> + <th ng-click="trackingFailures.changeSortOrder('date_first_occurred')">{{ 'General_Date'|translate }}</th> + <th ng-click="trackingFailures.changeSortOrder('url')">{{ 'Actions_ColumnPageURL'|translate }}</th> + <th ng-click="trackingFailures.changeSortOrder('request_url')">{{ 'CoreAdminHome_TrackingURL'|translate }}</th> + <th class="action">{{ 'General_Action'|translate }}</th> + </tr> + </thead> + <tbody> + <tr><td colspan="7" ng-show="!trackingFailures.isLoading && trackingFailures.failures.length == 0">{{'CoreAdminHome_NoKnownFailures'|translate}} <span class="icon-ok"></span></td></tr> + <tr ng-repeat="failure in trackingFailures.failures | orderBy:trackingFailures.sortColumn:trackingFailures.sortReverse"> + <td>{{ failure.site_name }} ({{'General_Id'|translate}} {{ failure.idsite }})</td> + <td>{{ failure.problem }}</td> + <td>{{ failure.solution }} <a ng-show="failure.solution_url" rel="noopener noreferrer" ng-href="{{ failure.solution_url }}">{{'CoreAdminHome_LearnMore'|translate }}</a></td> + <td class="datetime">{{ failure.pretty_date_first_occurred }}</td> + <td>{{ failure.url }}</td> + <td><span ng-show="!failure.showFullRequestUrl" title="{{'CoreHome_ClickToSeeFullInformation'|translate}}" + ng-click="failure.showFullRequestUrl = true">{{ failure.request_url|limitTo:100 }}...</span> + <span ng-show="failure.showFullRequestUrl">{{ failure.request_url }}</span></td> + <td><span class="table-action icon-delete" + title="{{'General_Delete'|translate}}" + ng-click="trackingFailures.deleteFailure(failure.idsite, failure.idfailure)"></span></td> + </tr> + </tbody> + </table> + + <div class="ui-confirm" id="confirmDeleteAllTrackingFailures"> + <h2>{{ 'CoreAdminHome_ConfirmDeleteAllTrackingFailures'|translate }}</h2> + + <input type="button" value="{{ 'General_Yes'|translate }}" role="yes"/> + <input type="button" value="{{ 'General_No'|translate }}" role="no" /> + </div> + + <div class="ui-confirm" id="confirmDeleteThisTrackingFailure"> + <h2>{{ 'CoreAdminHome_ConfirmDeleteThisTrackingFailure'|translate }}</h2> + + <input type="button" value="{{ 'General_Yes'|translate }}" role="yes"/> + <input type="button" value="{{ 'General_No'|translate }}" role="no" /> + </div> + +</div>
\ No newline at end of file diff --git a/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.js b/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.js new file mode 100644 index 0000000000..910e5278d7 --- /dev/null +++ b/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.js @@ -0,0 +1,25 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Usage: + * <div matomo-tracking-failures> + */ +(function () { + angular.module('piwikApp').directive('matomoTrackingFailures', matomoTrackingFailures); + + matomoTrackingFailures.$inject = ['piwik']; + + function matomoTrackingFailures(piwik){ + return { + restrict: 'A', + templateUrl: 'plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.html?cb=' + piwik.cacheBuster, + controller: 'TrackingFailuresController', + controllerAs: 'trackingFailures' + }; + } +})();
\ No newline at end of file diff --git a/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.less b/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.less new file mode 100644 index 0000000000..505b106431 --- /dev/null +++ b/plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.less @@ -0,0 +1,9 @@ +.matomoTrackingFailures { + .icon-delete, + th:not(.action) { + cursor: pointer; + } + th.action { + width: 60px; + } +}
\ No newline at end of file diff --git a/plugins/CoreAdminHome/config/test.php b/plugins/CoreAdminHome/config/test.php new file mode 100644 index 0000000000..13a2080dae --- /dev/null +++ b/plugins/CoreAdminHome/config/test.php @@ -0,0 +1,30 @@ +<?php +use \Piwik\Tracker\Request; +use \Piwik\Tracker\Failures; + +return array( + + 'Piwik\Tracker\Failures' => DI\decorate(function ($previous) { + /** @var Failures $previous */ + + $generate = \Piwik\Container\StaticContainer::get('test.vars.generateTrackingFailures'); + if ($generate) { + $previous->setNow(\Piwik\Date::factory('2018-07-07 01:02:03')); + $previous->logFailure(Failures::FAILURE_ID_INVALID_SITE, new Request(array( + 'idsite' => 998, 'rec' => '1' + ))); + $previous->logFailure(Failures::FAILURE_ID_NOT_AUTHENTICATED, new Request(array( + 'idsite' => 1, + 'url' => 'https://www.example.com/foo/bar?x=1', + 'action_name' => 'foobar', + 'rec' => '1' + ))); + $previous->logFailure(Failures::FAILURE_ID_INVALID_SITE, new Request(array( + 'idsite' => 999, 'rec' => '1' + ))); + } + + return $previous; + }), + +);
\ No newline at end of file diff --git a/plugins/CoreAdminHome/lang/en.json b/plugins/CoreAdminHome/lang/en.json index 25ae8e094f..ac3328f395 100644 --- a/plugins/CoreAdminHome/lang/en.json +++ b/plugins/CoreAdminHome/lang/en.json @@ -82,6 +82,7 @@ "PluginSettingsValueNotAllowed": "The value for field \"%1$s\" in plugin \"%2$s\" is not allowed", "PluginSettingsSaveFailed": "Failed to save plugin settings", "PluginSettingsSaveSuccess": "Plugin settings updated.", + "TrackingFailures": "Tracking failures", "SettingsSaveSuccess": "Settings updated.", "SendPluginUpdateCommunication": "Send an email when a plugin update is available", "SendPluginUpdateCommunicationHelp": "An email will be sent to Super Users when there is a new version available for a plugin.", @@ -108,6 +109,24 @@ "MissingTrackingCodeEmailSubject": "No traffic for %s recorded in Matomo Analytics, get started now", "JsTrackingCodeMissingEmail1": "A few days ago you added the website '%s' to your Matomo Analytics. We just checked and your Matomo doesn't seem to have any recorded traffic for this website.", "JsTrackingCodeMissingEmail2": "To begin tracking data and getting insights into your users, you'll need to setup tracking in your website or mobile app. For websites simply embed the tracking code right before the %s tag.", - "JsTrackingCodeMissingEmail3": "To find and customize your tracking code, %1$sclick here%2$s (or have a look at the %3$sJavaScript Tracking Client guide%4$s)." + "JsTrackingCodeMissingEmail3": "To find and customize your tracking code, %1$sclick here%2$s (or have a look at the %3$sJavaScript Tracking Client guide%4$s).", + "TrackingFailuresIntroduction": "This page lists tracking failures that happened during the last %s days. Please note that only the most common kind of tracking failures are recorded and not all of them.", + "NoKnownFailures": "There are no known tracking failures.", + "Problem": "Problem", + "Solution": "Solution", + "TrackingURL": "Tracking URL", + "LearnMore": "Learn more", + "DeleteAllFailures": "Delete all failures", + "NTrackingFailures": "%s tracking failures", + "ViewAllTrackingFailures": "View all tracking failures", + "TrackingFailureInvalidSiteProblem": "The site does not exist.", + "TrackingFailureInvalidSiteSolution": "Update the configured idSite in the tracker.", + "TrackingFailureAuthenticationProblem": "Request was not authenticated but authentication was required.", + "TrackingFailureAuthenticationSolution": "Set or correct a \"token_auth\" in your tracking request.", + "ConfirmDeleteAllTrackingFailures": "Are you sure you want to delete all tracking failures?", + "ConfirmDeleteThisTrackingFailure": "Are you sure you want to delete this tracking failure?", + "TrackingFailuresEmailSubject": "Tracking failures in your Matomo Analytics", + "TrackingFailuresEmail1": "This is just to let you know that %s different kinds of tracking failures have occurred in the last days.", + "TrackingFailuresEmail2": "To view all the failed tracking requests %1$sclick here%2$s." } } diff --git a/plugins/CoreAdminHome/templates/_trackingFailuresEmail.twig b/plugins/CoreAdminHome/templates/_trackingFailuresEmail.twig new file mode 100644 index 0000000000..8be51c0e0d --- /dev/null +++ b/plugins/CoreAdminHome/templates/_trackingFailuresEmail.twig @@ -0,0 +1,3 @@ +<p>{{ 'General_HelloUser'|translate(login) }}</p> +<p>{{ 'CoreAdminHome_TrackingFailuresEmail1'|translate('<strong>'~numFailures~'</strong>')|raw }}</p> +<p>{{ 'CoreAdminHome_TrackingFailuresEmail2'|translate('<a href="'~trackingFailuresUrl~'">', '</a>')|raw }}</p> diff --git a/plugins/CoreAdminHome/templates/getTrackingFailures.twig b/plugins/CoreAdminHome/templates/getTrackingFailures.twig new file mode 100644 index 0000000000..3096e65c2f --- /dev/null +++ b/plugins/CoreAdminHome/templates/getTrackingFailures.twig @@ -0,0 +1,13 @@ +<div class="widgetBody system-check"> + {% if numFailures == 0 %} + <p class="system-success"><span class="icon-ok"></span> {{ 'CoreAdminHome_NoKnownFailures'|translate }}</p> + {% else %} + <p class="system-errors"> + <span style="font-size: 16px;"><span class="icon-error"></span> {{ 'CoreAdminHome_NTrackingFailures'|translate(numFailures) }}</span> + </p> + <p> + <a href="{{ linkTo({'module': 'CoreAdminHome', 'action': 'trackingFailures'}) }}" + >{{ 'CoreAdminHome_ViewAllTrackingFailures'|translate }}</a> + </p> + {% endif %} +</div>
\ No newline at end of file diff --git a/plugins/CoreAdminHome/templates/home.twig b/plugins/CoreAdminHome/templates/home.twig index 58c3288c19..0c52fdf9c1 100644 --- a/plugins/CoreAdminHome/templates/home.twig +++ b/plugins/CoreAdminHome/templates/home.twig @@ -21,9 +21,14 @@ <div class="col s12 {% if isFeedbackEnabled %}m4{% else %}m6{% endif %}"> <div piwik-widget-loader='{"module":"CoreHome","action":"getSystemSummary"}'></div> </div> - {% if hasDiagnostics %} + {% if hasDiagnostics or hasTrackingFailures %} <div class="col s12 {% if isFeedbackEnabled %}m4{% else %}m6{% endif %}"> + {% if hasDiagnostics %} <div piwik-widget-loader='{"module":"Installation","action":"getSystemCheck"}'></div> + {% endif %} + {% if hasTrackingFailures %} + <div piwik-widget-loader='{"module":"CoreAdminHome","action":"getTrackingFailures"}'></div> + {% endif %} </div> {% endif %} {% if isFeedbackEnabled %} diff --git a/plugins/CoreAdminHome/templates/trackingFailures.twig b/plugins/CoreAdminHome/templates/trackingFailures.twig new file mode 100644 index 0000000000..36c2347e2e --- /dev/null +++ b/plugins/CoreAdminHome/templates/trackingFailures.twig @@ -0,0 +1,8 @@ +{% extends 'admin.twig' %} + +{% set title %}{{ 'CoreAdminHome_TrackingFailures'|translate }}{% endset %} + +{% block content %} + <div matomo-tracking-failures> + </div> +{% endblock %} diff --git a/plugins/CoreAdminHome/tests/Fixture/TrackingFailures.php b/plugins/CoreAdminHome/tests/Fixture/TrackingFailures.php new file mode 100644 index 0000000000..f8ab0cb808 --- /dev/null +++ b/plugins/CoreAdminHome/tests/Fixture/TrackingFailures.php @@ -0,0 +1,46 @@ +<?php +/** + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +namespace Piwik\Plugins\CoreAdminHome\tests\Fixture; + +use Piwik\Date; +use Piwik\Tests\Framework\Fixture; + +class TrackingFailures extends Fixture +{ + public $idSite = 1; + public $dateTime = '2013-01-02 03:04:05'; + + public function setUp() + { + parent::setUp(); + + Fixture::createSuperUser(); + if (!self::siteCreated($this->idSite)) { + Fixture::createWebsite('2014-01-02 03:04:05'); + } + $this->trackData(); + } + + private function trackData() + { + $t = self::getTracker($this->idSite, $this->dateTime, $defaultInit = true); + self::checkResponse($t->doTrackPageView('Valid Site')); + + $t = self::getTracker(99999, Date::now()->getDatetime(), $defaultInit = true); + + for ($i = 0; $i < 2; $i++) { + // we trigger it multiple times to test it will be inserted only once + $t->doTrackPageView('Invalid Site'); + } + + $t = self::getTracker($this->idSite, $this->dateTime, $defaultInit = true); + $t->setIp('10.11.12.13'); + $t->setTokenAuth('foobar'); // wrong token + $t->doTrackPageView('Invalid Token'); + } +}
\ No newline at end of file diff --git a/plugins/CoreAdminHome/tests/Fixtures/SimpleFixtureTrackFewVisits.php b/plugins/CoreAdminHome/tests/Fixtures/SimpleFixtureTrackFewVisits.php new file mode 100644 index 0000000000..b5c7fcf711 --- /dev/null +++ b/plugins/CoreAdminHome/tests/Fixtures/SimpleFixtureTrackFewVisits.php @@ -0,0 +1,77 @@ +<?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\Plugins\CoreAdminHome\tests\Fixtures; + +use Piwik\Date; +use Piwik\Tests\Framework\Fixture; + +/** + * Generates tracker testing data for our TrackingFailuresTest + * + * This Simple fixture adds one website and tracks one visit with couple pageviews and an ecommerce conversion + */ +class SimpleFixtureTrackFewVisits extends Fixture +{ + public $dateTime = '2013-01-23 01:23:45'; + public $idSite = 1; + + public function setUp() + { + $this->setUpWebsite(); + $this->trackFirstVisit(); + $this->trackSecondVisit(); + } + + public function tearDown() + { + // empty + } + + private function setUpWebsite() + { + if (!self::siteCreated($this->idSite)) { + $idSite = self::createWebsite($this->dateTime, $ecommerce = 1); + $this->assertSame($this->idSite, $idSite); + } + } + + protected function trackFirstVisit() + { + $t = self::getTracker($this->idSite, $this->dateTime, $defaultInit = true); + + $t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.1)->getDatetime()); + $t->setUrl('http://example.com/'); + self::checkResponse($t->doTrackPageView('Viewing homepage')); + + $t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.2)->getDatetime()); + $t->setUrl('http://example.com/sub/page'); + self::checkResponse($t->doTrackPageView('Second page view')); + + $t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.25)->getDatetime()); + $t->addEcommerceItem($sku = 'SKU_ID', $name = 'Test item!', $category = 'Test & Category', $price = 777, $quantity = 33); + self::checkResponse($t->doTrackEcommerceOrder('TestingOrder', $grandTotal = 33 * 77)); + } + + protected function trackSecondVisit() + { + $t = self::getTracker($this->idSite, $this->dateTime, $defaultInit = true); + $t->setIp('56.11.55.73'); + + $t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.1)->getDatetime()); + $t->setUrl('http://example.com/sub/page'); + self::checkResponse($t->doTrackPageView('Viewing homepage')); + + $t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.2)->getDatetime()); + $t->setUrl('http://example.com/?search=this is a site search query'); + self::checkResponse($t->doTrackPageView('Site search query')); + + $t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.3)->getDatetime()); + $t->addEcommerceItem($sku = 'SKU_ID2', $name = 'A durable item', $category = 'Best seller', $price = 321); + self::checkResponse($t->doTrackEcommerceCartUpdate($grandTotal = 33 * 77)); + } +}
\ No newline at end of file diff --git a/plugins/CoreAdminHome/tests/Integration/APITest.php b/plugins/CoreAdminHome/tests/Integration/APITest.php new file mode 100644 index 0000000000..a3ddf2a182 --- /dev/null +++ b/plugins/CoreAdminHome/tests/Integration/APITest.php @@ -0,0 +1,134 @@ +<?php +/** + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Plugins\CoreAdminHome\tests\Integration; + +use Piwik\Plugins\CoreAdminHome\API; +use Piwik\Tests\Framework\Fixture; +use Piwik\Tests\Framework\Mock\FakeAccess; + +/** + * @group CoreAdminHome + * @group APITest + * @group API + * @group Plugins + */ +class APITest extends \Piwik\Tests\Framework\TestCase\IntegrationTestCase +{ + /** + * @var int + */ + private $idSite; + + /** + * @var API + */ + private $api; + + public function setUp() + { + parent::setUp(); + $this->api = API::getInstance(); + for ($i = 0; $i < 5; $i++) { + Fixture::createWebsite('2014-01-02 03:04:05'); + } + } + + /** + * @expectedException \Piwik\NoAccessException + * @expectedExceptionMessage checkUserHasSomeAdminAccess + */ + public function test_getTrackingFailures_failsForViewUser() + { + $this->setUser(); + $this->api->getTrackingFailures(); + } + + public function test_getTrackingFailures_WorksForAdminAndSuperuser() + { + $this->setAdminUser(); + $this->assertSame(array(), $this->api->getTrackingFailures()); + $this->setSuperUser(); + $this->api->getTrackingFailures(); + $this->assertSame(array(), $this->api->getTrackingFailures()); + } + + /** + * @expectedException \Piwik\NoAccessException + * @expectedExceptionMessage checkUserHasSomeAdminAccess + */ + public function test_deleteAllTrackingFailures_failsForViewUser() + { + $this->setUser(); + $this->api->deleteAllTrackingFailures(); + } + + public function test_deleteAllTrackingFailures_WorksForAdminAndSuperuser() + { + $this->setAdminUser(); + $this->api->deleteAllTrackingFailures(); + $this->setSuperUser(); + $this->api->deleteAllTrackingFailures(); + } + + /** + * @expectedException \Piwik\NoAccessException + * @expectedExceptionMessage checkUserHasAdminAccess + */ + public function test_deleteTrackingFailure_failsForViewUser() + { + $this->setUser(); + $this->api->deleteTrackingFailure(1, 2); + } + + /** + * @expectedException \Piwik\NoAccessException + * @expectedExceptionMessage checkUserHasAdminAccess + */ + public function test_deleteTrackingFailure_failsForAdminUserIfNotAdminAccessToThatSite() + { + $this->setAdminUser(); + $this->api->deleteTrackingFailure(2, 2); + } + + public function test_deleteTrackingFailure_WorksForAdminAndSuperuser() + { + $this->setAdminUser(); + $this->api->deleteTrackingFailure(1, 2); + $this->setSuperUser(); + $this->api->deleteTrackingFailure(1, 2); + } + + protected function setSuperUser() + { + FakeAccess::clearAccess(true); + } + + protected function setUser() + { + FakeAccess::clearAccess(false); + FakeAccess::$identity = 'testUser'; + FakeAccess::$idSitesView = array(1,3, $this->idSite); + FakeAccess::$idSitesAdmin = array(); + } + + protected function setAdminUser() + { + FakeAccess::clearAccess(false); + FakeAccess::$identity = 'testUser'; + FakeAccess::$idSitesView = array(); + FakeAccess::$idSitesAdmin = array(1,3, $this->idSite); + } + + public function provideContainerConfig() + { + return array( + 'Piwik\Access' => new FakeAccess() + ); + } +} diff --git a/plugins/CoreAdminHome/tests/Integration/TasksTest.php b/plugins/CoreAdminHome/tests/Integration/TasksTest.php index d3ffc66518..ffab94c01d 100644 --- a/plugins/CoreAdminHome/tests/Integration/TasksTest.php +++ b/plugins/CoreAdminHome/tests/Integration/TasksTest.php @@ -14,12 +14,15 @@ use Piwik\Date; use Piwik\Db; use Piwik\Mail; use Piwik\Plugins\CoreAdminHome\Emails\JsTrackingCodeMissingEmail; +use Piwik\Plugins\CoreAdminHome\Emails\TrackingFailuresEmail; use Piwik\Plugins\CoreAdminHome\Tasks; use Piwik\Plugins\CoreAdminHome\Tasks\ArchivesToPurgeDistributedList; use Piwik\Scheduler\Task; use Piwik\Tests\Fixtures\RawArchiveDataWithTempAndInvalidated; use Piwik\Tests\Framework\Fixture; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; +use Piwik\Tracker\Failures; +use Piwik\Tracker\Request; use Psr\Log\NullLogger; /** @@ -66,7 +69,7 @@ class TasksTest extends IntegrationTestCase $archivePurger->setYesterdayDate(Date::factory('2015-02-26')); $archivePurger->setNow(Date::factory('2015-02-27 08:00:00')->getTimestamp()); - $this->tasks = new Tasks($archivePurger, new NullLogger()); + $this->tasks = new Tasks($archivePurger, new NullLogger(), new Failures()); $this->mail = null; } @@ -129,6 +132,8 @@ class TasksTest extends IntegrationTestCase 'purgeOutdatedArchives.', 'purgeInvalidatedArchives.', 'optimizeArchiveTable.', + 'cleanupTrackingFailures.', + 'notifyTrackingFailures.', 'updateSpammerBlacklist.', 'checkSiteHasTrackedVisits.2', 'checkSiteHasTrackedVisits.3', @@ -181,6 +186,35 @@ class TasksTest extends IntegrationTestCase $this->assertEquals($mail->getIdSite(), $idSite); } + public function test_cleanupTrackingFailures_doesNotCauseAnyException() + { + // it is only calling one method which is already tested... no need to write complex tests for it + $this->tasks->cleanupTrackingFailures(); + $this->assertTrue(true); + } + + public function test_notifyTrackingFailures_doesNotSendAnyMailWhenThereAreNoTrackingRequests() + { + $this->tasks->notifyTrackingFailures(); + $this->assertNull($this->mail); + } + + public function test_notifyTrackingFailures_sendsMailWhenThereAreTrackingFailures() + { + $failures = new Failures(); + $failures->logFailure(1, new Request(array('idsite' => 9999, 'rec' => 1))); + $failures->logFailure(1, new Request(array('idsite' => 9998, 'rec' => 1))); + Fixture::createSuperUser(false); + $this->tasks->notifyTrackingFailures(); + + /** @var TrackingFailuresEmail $mail */ + $mail = $this->mail; + $this->assertInstanceOf(TrackingFailuresEmail::class, $mail); + $this->assertEquals('superUserLogin', $mail->getLogin()); + $this->assertEquals('hello@example.org', $mail->getEmailAddress()); + $this->assertEquals(2, $mail->getNumFailures()); + } + /** * @param Date[] $dates */ diff --git a/plugins/CoreAdminHome/tests/System/TrackingFailuresTest.php b/plugins/CoreAdminHome/tests/System/TrackingFailuresTest.php new file mode 100644 index 0000000000..061c819e60 --- /dev/null +++ b/plugins/CoreAdminHome/tests/System/TrackingFailuresTest.php @@ -0,0 +1,63 @@ +<?php +/** + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Plugins\CoreAdminHome\tests\System; + +use Piwik\Plugins\CoreAdminHome\tests\Fixture\TrackingFailures; +use Piwik\Tests\Framework\TestCase\SystemTestCase; + +/** + * @group CoreAdminHome + * @group TrackingFailuresTest + * @group Plugins + */ +class TrackingFailuresTest extends SystemTestCase +{ + /** + * @var TrackingFailures + */ + public static $fixture = null; // initialized below class definition + + /** + * @dataProvider getApiForTesting + */ + public function testApi($api, $params) + { + $params['xmlFieldsToRemove'] = array('date_first_occurred', 'pretty_date_first_occurred', 'request_url'); + $this->runApiTests($api, $params); + } + + public function getApiForTesting() + { + $api = array( + 'CoreAdminHome.getTrackingFailures', + ); + + $apiToTest = array(); + $apiToTest[] = array($api, + array( + 'testSuffix' => '' + ) + ); + + return $apiToTest; + } + + public static function getOutputPrefix() + { + return ''; + } + + public static function getPathToTestDirectory() + { + return dirname(__FILE__); + } + +} + +TrackingFailuresTest::$fixture = new TrackingFailures();
\ No newline at end of file diff --git a/plugins/CoreAdminHome/tests/System/expected/test___CoreAdminHome.getTrackingFailures.xml b/plugins/CoreAdminHome/tests/System/expected/test___CoreAdminHome.getTrackingFailures.xml new file mode 100644 index 0000000000..511339901f --- /dev/null +++ b/plugins/CoreAdminHome/tests/System/expected/test___CoreAdminHome.getTrackingFailures.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <idsite>1</idsite> + <idfailure>2</idfailure> + + + <site_name>Piwik test</site_name> + + <url>http://example.com/piwik/</url> + <problem>Request was not authenticated but authentication was required.</problem> + <solution>Set or correct a "token_auth" in your tracking request.</solution> + <solution_url>https://matomo.org/faq/how-to/faq_30835/</solution_url> + </row> + <row> + <idsite>99999</idsite> + <idfailure>1</idfailure> + + + <site_name>Unknown</site_name> + + <url>http://example.com/piwik/</url> + <problem>The site does not exist.</problem> + <solution>Update the configured idSite in the tracker.</solution> + <solution_url>https://matomo.org/faq/how-to/faq_30838/</solution_url> + </row> +</result>
\ No newline at end of file diff --git a/plugins/CoreAdminHome/tests/UI/TrackingFailures_spec.js b/plugins/CoreAdminHome/tests/UI/TrackingFailures_spec.js new file mode 100644 index 0000000000..f98f1c0646 --- /dev/null +++ b/plugins/CoreAdminHome/tests/UI/TrackingFailures_spec.js @@ -0,0 +1,94 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +describe("TrackingFailures", function () { + this.timeout(0); + + var manageUrl = '?module=CoreAdminHome&action=trackingFailures&idSite=1&period=day&date=today'; + var widgetUrl = '?module=Widgetize&action=iframe&moduleToWidgetize=CoreAdminHome&actionToWidgetize=getTrackingFailures&idSite=1&period=day&date=today&widget=1'; + + function captureScreen(done, screenshotName, theTest) + { + expect.screenshot(screenshotName).to.be.captureSelector('.matomoTrackingFailures', theTest, done); + } + + function captureModal(done, screenshotName, theTest) + { + expect.screenshot(screenshotName).to.be.captureSelector('.modal.open', theTest, done); + } + + function generateTrackingFailures() + { + testEnvironment.generateTrackingFailures = 1; + testEnvironment.save(); + } + + function confirmModal(page) + { + page.click('.modal.open .modal-footer a:contains(Yes)'); + } + + afterEach(function () { + delete testEnvironment.generateTrackingFailures; + testEnvironment.save(); + }); + + it('should show widget with no failures', function (done) { + captureScreen(done, 'widget_no_failures', function (page) { + page.load(widgetUrl); + }); + }); + + it('should show manage page with no failures', function (done) { + captureScreen(done, 'manage_no_failures', function (page) { + page.load(manageUrl); + }); + }); + + it('should show widget with failures', function (done) { + generateTrackingFailures(); + captureScreen(done, 'widget_with_failures', function (page) { + generateTrackingFailures(); + page.load(widgetUrl); + }); + }); + + it('should show manage page with failures', function (done) { + generateTrackingFailures(); + captureScreen(done, 'manage_with_failures', function (page) { + generateTrackingFailures(); + page.load(manageUrl); + }); + }); + + it('should show ask to confirm delete one', function (done) { + captureModal(done, 'manage_with_failures_delete_one_ask_confirmation', function (page) { + page.evaluate(function () { + $('.matomoTrackingFailures table tbody tr:nth-child(2) .icon-delete').click() + }); + }); + }); + + it('should show delete when confirmed', function (done) { + captureScreen(done, 'manage_with_failures_delete_one_confirmed', function (page) { + confirmModal(page); + }); + }); + + it('should show ask to confirm delete all', function (done) { + captureModal(done, 'manage_with_failures_delete_all_ask_confirmation', function (page) { + page.click('.matomoTrackingFailures .deleteAllFailures'); + }); + }); + + it('should show ask to confirm delete one', function (done) { + captureScreen(done, 'manage_with_failures_delete_all_confirmed', function (page) { + confirmModal(page); + }); + }); + +});
\ No newline at end of file diff --git a/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_no_failures.png b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_no_failures.png new file mode 100644 index 0000000000..3652d932ca --- /dev/null +++ b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_no_failures.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:555956386a3960079e98fd0ed955ccf836d5aef1e9883f330ef08e43c496f3ff +size 25706 diff --git a/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures.png b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures.png new file mode 100644 index 0000000000..3920b896ea --- /dev/null +++ b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:164fc892e74d90ff316f76cc424dbb00e8af9f8ff5c487deaca4df67fb3b058d +size 75105 diff --git a/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_all_ask_confirmation.png b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_all_ask_confirmation.png new file mode 100644 index 0000000000..d087655199 --- /dev/null +++ b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_all_ask_confirmation.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a8c736bf8efa2dde7c14609ae473fddd4c09f616cbfa1d794bddcc01d12b707 +size 9554 diff --git a/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_all_confirmed.png b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_all_confirmed.png new file mode 100644 index 0000000000..3652d932ca --- /dev/null +++ b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_all_confirmed.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:555956386a3960079e98fd0ed955ccf836d5aef1e9883f330ef08e43c496f3ff +size 25706 diff --git a/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_one_ask_confirmation.png b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_one_ask_confirmation.png new file mode 100644 index 0000000000..372005bf86 --- /dev/null +++ b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_one_ask_confirmation.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3a773a094fe4a81c031a71ad279ccda03cee6f3b8139ed6bbaac27c6ea8ff7c4 +size 9585 diff --git a/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_one_confirmed.png b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_one_confirmed.png new file mode 100644 index 0000000000..237b4c9a7a --- /dev/null +++ b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_manage_with_failures_delete_one_confirmed.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32619750eb571199b8fb5b0761efe64d46f9db3dd090b7f8bbc7a1151aa5e295 +size 48513 diff --git a/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_widget_no_failures.png b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_widget_no_failures.png new file mode 100644 index 0000000000..c610efccb2 --- /dev/null +++ b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_widget_no_failures.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8151ae81cc83466e763346f02b272dc7ec480832d49807f59cfb32a53630da6a +size 11165 diff --git a/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_widget_with_failures.png b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_widget_with_failures.png new file mode 100644 index 0000000000..fc40fbe9b1 --- /dev/null +++ b/plugins/CoreAdminHome/tests/UI/expected-screenshots/TrackingFailures_widget_with_failures.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a98049c33bb5cab09436985b5cf062a931560028014f8c9f8b1ccc0d50c3af8 +size 12805 diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php index 76e933ae51..ab11a468eb 100644 --- a/plugins/CoreHome/CoreHome.php +++ b/plugins/CoreHome/CoreHome.php @@ -287,6 +287,8 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreAdminHome/angularjs/trackingcode/jstrackingcode.controller.js"; $jsFiles[] = "plugins/CoreAdminHome/angularjs/trackingcode/imagetrackingcode.controller.js"; $jsFiles[] = "plugins/CoreAdminHome/angularjs/archiving/archiving.controller.js"; + $jsFiles[] = "plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.controller.js"; + $jsFiles[] = "plugins/CoreAdminHome/angularjs/trackingfailures/trackingfailures.directive.js"; // we have to load these CorePluginsAdmin files here. If we loaded them in CorePluginsAdmin, // there would be JS errors as CorePluginsAdmin is loaded first. Meaning it is loaded before diff --git a/plugins/CoreHome/Tracker/VisitRequestProcessor.php b/plugins/CoreHome/Tracker/VisitRequestProcessor.php index 033399e196..c2a88e93d4 100644 --- a/plugins/CoreHome/Tracker/VisitRequestProcessor.php +++ b/plugins/CoreHome/Tracker/VisitRequestProcessor.php @@ -88,7 +88,10 @@ class VisitRequestProcessor extends RequestProcessor $visitProperties->setProperty('location_ip', $request->getIp()); $excluded = new VisitExcluded($request); - if ($excluded->isExcluded()) { + $isExcluded = $excluded->isExcluded(); + $request->setMetadata('CoreHome', 'isVisitExcluded', $isExcluded); + + if ($isExcluded) { return true; } diff --git a/plugins/CustomVariables/tests/UI/expected-screenshots/CustomVariables_link_in_menu.png b/plugins/CustomVariables/tests/UI/expected-screenshots/CustomVariables_link_in_menu.png index 62e1cb3583..ea9a6fe395 100644 --- a/plugins/CustomVariables/tests/UI/expected-screenshots/CustomVariables_link_in_menu.png +++ b/plugins/CustomVariables/tests/UI/expected-screenshots/CustomVariables_link_in_menu.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08217344adea43733531372ee479b5f11dc6f67d7ac40f07284e8feaae5b3c8a -size 14959 +oid sha256:f7798c4e443bd838de905511c77f82899e44d4d2e990e5623ee2fd0b2a09c79d +size 16695 diff --git a/plugins/QueuedTracking b/plugins/QueuedTracking -Subproject 49e30794fcf0a77bac7cef9e5c779e855453549 +Subproject 7609e1bd46b5da8f8e638c01dc71fb782dffdb9 diff --git a/plugins/SitesManager/SitesManager.php b/plugins/SitesManager/SitesManager.php index 76576f84ed..054ecc2fce 100644 --- a/plugins/SitesManager/SitesManager.php +++ b/plugins/SitesManager/SitesManager.php @@ -8,9 +8,11 @@ */ namespace Piwik\Plugins\SitesManager; +use Piwik\Access; use Piwik\API\Request; use Piwik\Common; use Piwik\Container\StaticContainer; +use Piwik\Exception\UnexpectedWebsiteFoundException; use Piwik\Piwik; use Piwik\Plugins\CoreHome\SystemSummary; use Piwik\Plugins\PrivacyManager\PrivacyManager; @@ -36,7 +38,8 @@ class SitesManager extends \Piwik\Plugin return array( 'AssetManager.getJavaScriptFiles' => 'getJsFiles', 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles', - 'Tracker.Cache.getSiteAttributes' => 'recordWebsiteDataInCache', + 'Tracker.Cache.getSiteAttributes' => array('function' => 'recordWebsiteDataInCache', 'before' => true), + 'Tracker.setTrackerCacheGeneral' => 'setTrackerCacheGeneral', 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', 'SitesManager.deleteSite.end' => 'onSiteDeleted', 'System.addSystemSummaryItems' => 'addSystemSummaryItems', @@ -145,13 +148,13 @@ class SitesManager extends \Piwik\Plugin { $idSite = (int) $idSite; + $website = API::getInstance()->getSiteFromId($idSite); $urls = API::getInstance()->getSiteUrlsFromId($idSite); // add the 'hosts' entry in the website array $array['urls'] = $urls; $array['hosts'] = $this->getTrackerHosts($urls); - $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); @@ -165,6 +168,14 @@ class SitesManager extends \Piwik\Plugin $array['type'] = $website['type']; } + public function setTrackerCacheGeneral(&$cache) + { + Access::doAsSuperUser(function () use (&$cache) { + $cache['global_excluded_user_agents'] = self::filterBlankFromCommaSepList(API::getInstance()->getExcludedUserAgentsGlobal()); + $cache['global_excluded_ips'] = self::filterBlankFromCommaSepList(API::getInstance()->getExcludedIpsGlobal()); + }); + } + /** * Returns whether we should keep URL fragments for a specific site. * diff --git a/plugins/Widgetize/tests/System/WidgetTest.php b/plugins/Widgetize/tests/System/WidgetTest.php index cdf8fe54ff..96b78dd70b 100644 --- a/plugins/Widgetize/tests/System/WidgetTest.php +++ b/plugins/Widgetize/tests/System/WidgetTest.php @@ -1016,6 +1016,14 @@ class WidgetTest extends SystemTestCase 'action' => 'getSystemCheck', ), ), array ( + 'name' => 'Tracking failures', + 'uniqueId' => 'widgetCoreAdminHomegetTrackingFailures', + 'parameters' => + array ( + 'module' => 'CoreAdminHome', + 'action' => 'getTrackingFailures', + ), + ), array ( 'name' => 'System Summary', 'uniqueId' => 'widgetCoreHomegetSystemSummary', 'parameters' => |