diff options
author | Matthieu Aubry <mattab@users.noreply.github.com> | 2016-09-26 06:26:55 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-26 06:26:55 +0300 |
commit | a8f682a6039e9b765e248c6be531cce54a7903d1 (patch) | |
tree | d242720e47a1aaff0c0cd020d238a1e7715c564f | |
parent | 10486f8e9e4cae49be7202cf797105fbd58555b5 (diff) |
Release 2.16.3-b4 (#10558)2.16.3-b4
* Fix Scheduled Reports sent one hour late in daylight saving timezones (#10443)
* convert hour to send report to/from UTC, to ensure it isn't affected by daylight savings
* adds update script to change existing scheduled reports to use utc time
* code improvement
* adds missing param
* Added new event Archiving.makeNewArchiverObject to allow customising plugin archiving (#10366)
* added hook to alllow plugin archiving prevention
* cr code style notes
* reworked PR to fit CR suggestions
* added PHPDoc for hook
* Event description more consistent
* UI tests: minor changes
* Adds test checking if all screenshots are stored in lfs
* removed screenshots not stored in lfs
* readds screenshots to lfs
* 2.16.3-b4
-rw-r--r-- | core/ArchiveProcessor/PluginsArchiver.php | 38 | ||||
-rw-r--r-- | core/Plugin/Archiver.php | 13 | ||||
-rw-r--r-- | core/Updates/2.16.3-b3.php | 41 | ||||
-rw-r--r-- | core/Version.php | 2 | ||||
-rw-r--r-- | plugins/ScheduledReports/Controller.php | 6 | ||||
-rw-r--r-- | plugins/ScheduledReports/Tasks.php | 4 | ||||
-rw-r--r-- | plugins/ScheduledReports/javascripts/pdf.js | 15 | ||||
-rw-r--r-- | plugins/ScheduledReports/lang/en.json | 1 | ||||
-rw-r--r-- | plugins/ScheduledReports/stylesheets/scheduledreports.less | 3 | ||||
-rw-r--r-- | plugins/ScheduledReports/templates/_addReport.twig | 15 | ||||
-rw-r--r-- | plugins/ScheduledReports/templates/index.twig | 1 | ||||
-rw-r--r-- | plugins/ScheduledReports/tests/Integration/ApiTest.php | 17 | ||||
-rw-r--r-- | tests/PHPUnit/Integration/ReleaseCheckListTest.php | 19 | ||||
-rw-r--r-- | tests/UI/expected-screenshots/CoreUpdaterDb_main.png | bin | 125710 -> 131 bytes | |||
-rw-r--r-- | tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png | 4 | ||||
-rw-r--r-- | tests/UI/expected-screenshots/UIIntegrationTest_email_reports.png | 4 | ||||
m--------- | tests/travis | 0 |
17 files changed, 155 insertions, 28 deletions
diff --git a/core/ArchiveProcessor/PluginsArchiver.php b/core/ArchiveProcessor/PluginsArchiver.php index 28c90cb15c..325b529aa3 100644 --- a/core/ArchiveProcessor/PluginsArchiver.php +++ b/core/ArchiveProcessor/PluginsArchiver.php @@ -10,10 +10,12 @@ namespace Piwik\ArchiveProcessor; use Piwik\ArchiveProcessor; +use Piwik\Common; use Piwik\DataAccess\ArchiveWriter; use Piwik\DataAccess\LogAggregator; use Piwik\DataTable\Manager; use Piwik\Metrics; +use Piwik\Piwik; use Piwik\Plugin\Archiver; use Piwik\Log; use Piwik\Timer; @@ -50,8 +52,8 @@ class PluginsArchiver public function __construct(Parameters $params, $isTemporaryArchive) { $this->params = $params; - - $this->archiveWriter = new ArchiveWriter($this->params, $isTemporaryArchive); + $this->isTemporaryArchive = $isTemporaryArchive; + $this->archiveWriter = new ArchiveWriter($this->params, $this->isTemporaryArchive); $this->archiveWriter->initNewArchive(); $this->logAggregator = new LogAggregator($params); @@ -106,7 +108,7 @@ class PluginsArchiver $latestUsedTableId = Manager::getInstance()->getMostRecentTableId(); /** @var Archiver $archiver */ - $archiver = new $archiverClass($this->archiveProcessor); + $archiver = $this->makeNewArchiverObject($archiverClass, $pluginName); if (!$archiver->isEnabled()) { Log::debug("PluginsArchiver::%s: Skipping archiving for plugin '%s'.", __FUNCTION__, $pluginName); @@ -198,9 +200,9 @@ class PluginsArchiver return true; } if (Rules::shouldProcessReportsAllPlugins( - $this->params->getIdSites(), - $this->params->getSegment(), - $this->params->getPeriod()->getLabel())) { + $this->params->getIdSites(), + $this->params->getSegment(), + $this->params->getPeriod()->getLabel())) { return true; } @@ -236,4 +238,28 @@ class PluginsArchiver $metrics = $this->archiveProcessor->aggregateNumericMetrics($toSum); return $metrics; } + + + /** + * @param $archiverClass + * @return Archiver + */ + private function makeNewArchiverObject($archiverClass, $pluginName) + { + $archiver = new $archiverClass($this->archiveProcessor); + + /** + * Triggered right after a new **plugin archiver instance** is created. + * Subscribers to this event can configure the plugin archiver, for example prevent the archiving of a plugin's data + * by calling `$archiver->disable()` method. + * + * @param \Piwik\Plugin\Archiver &$archiver The newly created plugin archiver instance. + * @param string $pluginName The name of plugin of which archiver instance was created. + * @param array $this->params Array containing archive parameters (Site, Period, Date and Segment) + * @param bool $this->isTemporaryArchive Flag indicating whether the archive being processed is temporary (ie. the period isn't finished yet) or final (the period is already finished and in the past). + */ + Piwik::postEvent('Archiving.makeNewArchiverObject', array($archiver, $pluginName, $this->params, $this->isTemporaryArchive)); + + return $archiver; + } } diff --git a/core/Plugin/Archiver.php b/core/Plugin/Archiver.php index 7cc9fe26f5..90e325bc8e 100644 --- a/core/Plugin/Archiver.php +++ b/core/Plugin/Archiver.php @@ -60,6 +60,11 @@ abstract class Archiver private $processor; /** + * @var bool + */ + private $enabled; + + /** * Constructor. * * @param ArchiveProcessor $processor The ArchiveProcessor instance to use when persisting archive @@ -69,6 +74,7 @@ abstract class Archiver { $this->maximumRows = PiwikConfig::getInstance()->General['datatable_archiving_maximum_rows_standard']; $this->processor = $processor; + $this->enabled = true; } /** @@ -121,6 +127,11 @@ abstract class Archiver return $this->getProcessor()->getLogAggregator(); } + public function disable() + { + $this->enabled = false; + } + /** * Whether this Archiver should be used or not. * @@ -128,6 +139,6 @@ abstract class Archiver */ public function isEnabled() { - return true; + return $this->enabled; } } diff --git a/core/Updates/2.16.3-b3.php b/core/Updates/2.16.3-b3.php new file mode 100644 index 0000000000..a1175c9f4d --- /dev/null +++ b/core/Updates/2.16.3-b3.php @@ -0,0 +1,41 @@ +<?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\Plugins\ScheduledReports\API as ScheduledReportsAPI; +use Piwik\Plugins\ScheduledReports\Model as ScheduledReportsModel; +use Piwik\Site; +use Piwik\Updater; +use Piwik\Updates as PiwikUpdates; + +/** + * Update for version 2.16.3-b3. + * + * Update existing scheduled reports to use UTC timezone for hour setting + */ +class Updates_2_16_3_b3 extends PiwikUpdates +{ + public function doUpdate(Updater $updater) + { + $model = new ScheduledReportsModel(); + $allReports = ScheduledReportsAPI::getInstance()->getReports(); + foreach ($allReports as $report) { + $report['hour'] = $this->adjustTimezoneBySite($report['hour'], $report['idsite']); + $model->updateReport($report['idreport'], $report); + } + } + + protected function adjustTimezoneBySite($hour, $idSite) + { + $timezone = Site::getTimezoneFor($idSite); + $dateTimeZone = new \DateTimeZone($timezone); + $timeZoneDifference = -ceil($dateTimeZone->getOffset(new \DateTime()) / 3600); + return (24 + $hour + $timeZoneDifference) % 24; + } +} diff --git a/core/Version.php b/core/Version.php index c96dce0e86..2cf7565c10 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.16.3-b3'; + const VERSION = '2.16.3-b4'; public function isStableVersion($version) { diff --git a/plugins/ScheduledReports/Controller.php b/plugins/ScheduledReports/Controller.php index 3192a3cfc4..7316f6283d 100644 --- a/plugins/ScheduledReports/Controller.php +++ b/plugins/ScheduledReports/Controller.php @@ -26,7 +26,11 @@ class Controller extends \Piwik\Plugin\Controller $view = new View('@ScheduledReports/index'); $this->setGeneralVariablesView($view); - $view->countWebsites = count(APISitesManager::getInstance()->getSitesIdWithAtLeastViewAccess()); + $siteTimezone = $this->site->getTimezone(); + $dateTimeZone = new \DateTimeZone($siteTimezone); + + $view->timeZoneDifference = $dateTimeZone->getOffset(new \DateTime()) / 3600; + $view->countWebsites = count(APISitesManager::getInstance()->getSitesIdWithAtLeastViewAccess()); // get report types $reportTypes = API::getReportTypes(); diff --git a/plugins/ScheduledReports/Tasks.php b/plugins/ScheduledReports/Tasks.php index be61e0d793..44a13e1b57 100644 --- a/plugins/ScheduledReports/Tasks.php +++ b/plugins/ScheduledReports/Tasks.php @@ -18,11 +18,9 @@ class Tasks extends \Piwik\Plugin\Tasks foreach (API::getInstance()->getReports() as $report) { if (!$report['deleted'] && $report['period'] != Schedule::PERIOD_NEVER) { - $timezone = Site::getTimezoneFor($report['idsite']); - $schedule = Schedule::getScheduledTimeForPeriod($report['period']); $schedule->setHour($report['hour']); - $schedule->setTimezone($timezone); + $schedule->setTimezone('UTC'); // saved hour is UTC always $this->custom(API::getInstance(), 'sendReport', $report['idreport'], $schedule); } diff --git a/plugins/ScheduledReports/javascripts/pdf.js b/plugins/ScheduledReports/javascripts/pdf.js index 2b86809517..5ddff3654f 100644 --- a/plugins/ScheduledReports/javascripts/pdf.js +++ b/plugins/ScheduledReports/javascripts/pdf.js @@ -9,6 +9,10 @@ var getReportParametersFunctions = Object(); var updateReportParametersFunctions = Object(); var resetReportParametersFunctions = Object(); +function adjustHourToTimezone(hour, difference) { + return (24 + parseInt(hour) + difference) % 24; +} + function formSetEditReport(idReport) { var report = { 'type': ReportPlugin.defaultReportType, @@ -29,11 +33,16 @@ function formSetEditReport(idReport) { toggleReportType(report.type); + var hour = adjustHourToTimezone(report.hour, timeZoneDifference); + $('#report_description').html(report.description); $('#report_segment').find('option[value=' + report.idsegment + ']').prop('selected', 'selected'); $('#report_type').find('option[value=' + report.type + ']').prop('selected', 'selected'); $('#report_period').find('option[value=' + report.period + ']').prop('selected', 'selected'); - $('#report_hour').val(report.hour); + $('#report_hour').val(hour).bind('change', function() { + $('#hour_utc').text(adjustHourToTimezone($(this).val(), -timeZoneDifference)); + }); + $('#hour_utc').text(report.hour); $('[name=report_format].' + report.type + ' option[value=' + report.format + ']').prop('selected', 'selected'); $('select[name=report_type]').change( toggleDisplayOptionsByFormat ); @@ -122,10 +131,12 @@ function initManagePdf() { apiParameters.parameters = getReportParametersFunctions[apiParameters.reportType](); + var hour = adjustHourToTimezone($('#report_hour').val(), -timeZoneDifference); + var ajaxHandler = new ajaxHelper(); ajaxHandler.addParams(apiParameters, 'POST'); ajaxHandler.addParams({period: $('#report_period').find('option:selected').val()}, 'GET'); - ajaxHandler.addParams({hour: $('#report_hour').val()}, 'GET'); + ajaxHandler.addParams({hour: hour}, 'GET'); ajaxHandler.redirectOnSuccess(); ajaxHandler.setLoadingElement(); if (idReport) { diff --git a/plugins/ScheduledReports/lang/en.json b/plugins/ScheduledReports/lang/en.json index a1ef702c9a..60f0254a0d 100644 --- a/plugins/ScheduledReports/lang/en.json +++ b/plugins/ScheduledReports/lang/en.json @@ -29,6 +29,7 @@ "PluginDescription": "Create custom reports and schedule them to be emailed daily, weekly or monthly to one or several people. Several report formats are supported (html, pdf, csv, images).", "ReportFormat": "Report Format", "ReportHour": "Send report at %s o'clock", + "ReportHourWithUTC": "Send report at %1$s o'clock (%2$s o'clock UTC)", "ReportIncludeNWebsites": "The report will include main metrics for all websites that have at least one visit (from the %s websites currently available).", "ReportSent": "Report sent", "ReportsIncluded": "Statistics included", diff --git a/plugins/ScheduledReports/stylesheets/scheduledreports.less b/plugins/ScheduledReports/stylesheets/scheduledreports.less index 871b89da3c..27d2d1557d 100644 --- a/plugins/ScheduledReports/stylesheets/scheduledreports.less +++ b/plugins/ScheduledReports/stylesheets/scheduledreports.less @@ -7,5 +7,6 @@ #report_hour { height: 0.9em; padding: 0 0 0 5px; - width: 35px; + width: 45px; + background-position: 25px center; } diff --git a/plugins/ScheduledReports/templates/_addReport.twig b/plugins/ScheduledReports/templates/_addReport.twig index 24f97ad19f..7ed8a0c588 100644 --- a/plugins/ScheduledReports/templates/_addReport.twig +++ b/plugins/ScheduledReports/templates/_addReport.twig @@ -59,7 +59,20 @@ <br/> {{ 'ScheduledReports_MonthlyScheduleHelp'|translate }} <br/> - {{ 'ScheduledReports_ReportHour'|translate('<input type="text" id="report_hour" class="inp" size="2">')|raw }} + + {% set hourInput %} + <select id="report_hour"> + {% for i in 0..23 %} + <option value="{{ i }}">{{ i }}</option> + {% endfor %} + </select> + {% endset %} + + {% if timeZoneDifference != 0 %} + {{ 'ScheduledReports_ReportHourWithUTC'|translate(hourInput, '<span id="hour_utc"></span>')|raw }} + {% else %} + {{ 'ScheduledReports_ReportHour'|translate(hourInput)|raw }} + {% endif %} </div> </td> </tr> diff --git a/plugins/ScheduledReports/templates/index.twig b/plugins/ScheduledReports/templates/index.twig index 542fab8e70..b98ee70fc5 100644 --- a/plugins/ScheduledReports/templates/index.twig +++ b/plugins/ScheduledReports/templates/index.twig @@ -32,6 +32,7 @@ </div> <script type="text/javascript"> + var timeZoneDifference = {{ timeZoneDifference }}; var ReportPlugin = {}; ReportPlugin.defaultPeriod = '{{ defaultPeriod }}'; ReportPlugin.defaultHour = '{{ defaultHour }}'; diff --git a/plugins/ScheduledReports/tests/Integration/ApiTest.php b/plugins/ScheduledReports/tests/Integration/ApiTest.php index e2d242581f..07d851a694 100644 --- a/plugins/ScheduledReports/tests/Integration/ApiTest.php +++ b/plugins/ScheduledReports/tests/Integration/ApiTest.php @@ -371,21 +371,22 @@ class ApiTest extends IntegrationTestCase )); // expected tasks + // NOTE: scheduled reports are always saved with UTC, to avoid daylight saving issues $scheduleTask1 = Schedule::factory('daily'); - $scheduleTask1->setHour(0); // paris is UTC-1, period ends at 23h UTC - $scheduleTask1->setTimezone('Europe/Paris'); + $scheduleTask1->setHour(0); + $scheduleTask1->setTimezone('UTC'); $scheduleTask2 = new Monthly(); - $scheduleTask2->setHour(0); // site is UTC-6.5, period ends at 6h30 UTC, smallest resolution is hour - $scheduleTask2->setTimezone('UTC-6.5'); + $scheduleTask2->setHour(0); + $scheduleTask2->setTimezone('UTC'); $scheduleTask3 = new Monthly(); - $scheduleTask3->setHour(8); // paris is UTC-1, configured to be sent at 8h - $scheduleTask3->setTimezone('Europe/Paris'); + $scheduleTask3->setHour(8); + $scheduleTask3->setTimezone('UTC'); $scheduleTask4 = new Monthly(); - $scheduleTask4->setHour(8); // site is UTC-6.5, configured to be sent at 8h - $scheduleTask4->setTimezone('UTC-6.5'); + $scheduleTask4->setHour(8); + $scheduleTask4->setTimezone('UTC'); $expectedTasks = array( new Task(APIScheduledReports::getInstance(), 'sendReport', 1, $scheduleTask1), diff --git a/tests/PHPUnit/Integration/ReleaseCheckListTest.php b/tests/PHPUnit/Integration/ReleaseCheckListTest.php index 88bbb8e1b7..b90e5c2732 100644 --- a/tests/PHPUnit/Integration/ReleaseCheckListTest.php +++ b/tests/PHPUnit/Integration/ReleaseCheckListTest.php @@ -91,6 +91,25 @@ class ReleaseCheckListTest extends \PHPUnit_Framework_TestCase $this->checkFilesAreInJpgFormat($files); } + public function test_screenshotsStoredInLfs() + { + $screenshots = Filesystem::globr(PIWIK_INCLUDE_PATH . '/tests/UI/expected-screenshots', '*.png'); + $cleanPath = function ($value) { + return str_replace(PIWIK_INCLUDE_PATH . '/', '', $value); + }; + $screenshots = array_map($cleanPath, $screenshots); + + $storedLfsFiles = explode("\n", `git lfs ls-files`); + $cleanRevision = function ($value) { + $parts = explode(' - ', $value); + return array_pop($parts); + }; + $storedLfsFiles = array_map($cleanRevision, $storedLfsFiles); + + $diff = array_diff($screenshots, $storedLfsFiles); + $this->assertEmpty($diff, 'Some Screenshots are not stored in LFS: ' . implode("\n", $diff)); + } + public function testCheckThatConfigurationValuesAreProductionValues() { $this->_checkEqual(array('Debug' => 'always_archive_data_day'), '0'); diff --git a/tests/UI/expected-screenshots/CoreUpdaterDb_main.png b/tests/UI/expected-screenshots/CoreUpdaterDb_main.png Binary files differindex 1d6c95541a..e0d8eee6a2 100644 --- a/tests/UI/expected-screenshots/CoreUpdaterDb_main.png +++ b/tests/UI/expected-screenshots/CoreUpdaterDb_main.png diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png b/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png index 25d961246e..78ce53c3c5 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bbfcce8a0c674db8f725104077ffdca606292f746de18dd7443dab68d9d56618 -size 2480230 +oid sha256:0a3ca67fd0848a4c3ac8d0fde79d385adec65115eff3b0df6cf534bc1c851282 +size 2494420 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_email_reports.png b/tests/UI/expected-screenshots/UIIntegrationTest_email_reports.png index 6dfc2e26d1..7e1ed37236 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_email_reports.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_email_reports.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a06b95792a06fd8f3585c6a347381765fb891a59bf7b76138b15fc551bb55972 -size 52520 +oid sha256:b60aa9a3254e6209a08bd76f38a6e0ed15aee0a85018937eecfefa7cddb82d46 +size 48768 diff --git a/tests/travis b/tests/travis -Subproject e0d3e68c0310e605bd654748676e8cb4c9bf0c1 +Subproject e041bdf1a6b63024478852a58a69dd826e8aca4 |