diff options
-rw-r--r-- | core/API/ResponseBuilder.php | 8 | ||||
-rw-r--r-- | core/ExceptionHandler.php | 7 | ||||
-rw-r--r-- | core/Http/BadRequestException.php | 18 | ||||
-rw-r--r-- | core/Http/HttpCodeException.php | 13 | ||||
-rw-r--r-- | core/Plugin/Visualization.php | 22 | ||||
-rw-r--r-- | core/ViewDataTable/RequestConfig.php | 10 | ||||
-rw-r--r-- | plugins/CoreVisualizations/Visualizations/Cloud.php | 5 | ||||
-rw-r--r-- | plugins/CoreVisualizations/Visualizations/HtmlTable.php | 5 | ||||
-rw-r--r-- | plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php | 2 | ||||
-rw-r--r-- | plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php | 2 | ||||
-rw-r--r-- | plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php | 2 | ||||
-rw-r--r-- | plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php | 2 | ||||
-rw-r--r-- | plugins/ScheduledReports/API.php | 12 | ||||
-rw-r--r-- | plugins/ScheduledReports/tests/Integration/ApiTest.php | 26 |
14 files changed, 133 insertions, 1 deletions
diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php index bbdd63c103..dd00426999 100644 --- a/core/API/ResponseBuilder.php +++ b/core/API/ResponseBuilder.php @@ -15,6 +15,7 @@ use Piwik\DataTable\Renderer; use Piwik\DataTable\DataTableInterface; use Piwik\DataTable\Filter\ColumnDelete; use Piwik\DataTable\Filter\Pattern; +use Piwik\Http\HttpCodeException; use Piwik\Plugins\Monolog\Processor\ExceptionToTextProcessor; /** @@ -135,6 +136,13 @@ class ResponseBuilder $e = $this->decorateExceptionWithDebugTrace($e); $message = $this->formatExceptionMessage($e); + if ($this->sendHeader + && $e instanceof HttpCodeException + && $e->getCode() > 0 + ) { + http_response_code($e->getCode()); + } + $this->sendHeaderIfEnabled(); return $this->apiRenderer->renderException($message, $e); diff --git a/core/ExceptionHandler.php b/core/ExceptionHandler.php index c1f959ce6d..9dfb1155d3 100644 --- a/core/ExceptionHandler.php +++ b/core/ExceptionHandler.php @@ -13,6 +13,7 @@ use Interop\Container\Exception\ContainerException; use Piwik\API\Request; use Piwik\API\ResponseBuilder; use Piwik\Container\ContainerDoesNotExistException; +use Piwik\Http\HttpCodeException; use Piwik\Container\StaticContainer; use Piwik\Plugins\CoreAdminHome\CustomLogo; use Psr\Log\LoggerInterface; @@ -70,6 +71,12 @@ class ExceptionHandler */ public static function dieWithHtmlErrorPage($exception) { + if ($exception instanceof HttpCodeException + && $exception->getCode() > 0 + ) { + http_response_code($exception->getCode()); + } + self::logException($exception); Common::sendHeader('Content-Type: text/html; charset=utf-8'); diff --git a/core/Http/BadRequestException.php b/core/Http/BadRequestException.php new file mode 100644 index 0000000000..5f5bb69d74 --- /dev/null +++ b/core/Http/BadRequestException.php @@ -0,0 +1,18 @@ +<?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\Http; + + +class BadRequestException extends HttpCodeException +{ + public function __construct($message) + { + parent::__construct($message, $code = 400); + } +}
\ No newline at end of file diff --git a/core/Http/HttpCodeException.php b/core/Http/HttpCodeException.php new file mode 100644 index 0000000000..cd91e0f490 --- /dev/null +++ b/core/Http/HttpCodeException.php @@ -0,0 +1,13 @@ +<?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\Http; + +class HttpCodeException extends \Exception +{ +}
\ No newline at end of file diff --git a/core/Plugin/Visualization.php b/core/Plugin/Visualization.php index f23a183ed6..f8e06a5702 100644 --- a/core/Plugin/Visualization.php +++ b/core/Plugin/Visualization.php @@ -17,10 +17,12 @@ use Piwik\Common; use Piwik\Container\StaticContainer; use Piwik\DataTable; use Piwik\Date; +use Piwik\Http\BadRequestException; use Piwik\Log; use Piwik\Metrics\Formatter\Html as HtmlFormatter; use Piwik\NoAccessException; use Piwik\Option; +use Piwik\Period; use Piwik\Piwik; use Piwik\Plugins\API\API as ApiApi; use Piwik\Plugins\PrivacyManager\PrivacyManager; @@ -254,6 +256,26 @@ class Visualization extends ViewDataTable return $view->render(); } + protected function checkRequestIsNotForMultiplePeriods() + { + $date = $this->requestConfig->getRequestParam('date'); + $period = $this->requestConfig->getRequestParam('period'); + if (Period::isMultiplePeriod($date, $period)) { + throw new BadRequestException("The '" . static::ID . "' visualization does not support multiple periods."); + } + } + + protected function checkRequestIsOnlyForMultiplePeriods() + { + try { + $this->checkRequestIsNotForMultiplePeriods(); + } catch (BadRequestException $ex) { + return; // ignore + } + + throw new BadRequestException("The '" . static::ID . "' visualization does not support single periods."); + } + private function hasAnyData(DataTable\DataTableInterface $dataTable) { $hasData = false; diff --git a/core/ViewDataTable/RequestConfig.php b/core/ViewDataTable/RequestConfig.php index 937624a358..42df4c406b 100644 --- a/core/ViewDataTable/RequestConfig.php +++ b/core/ViewDataTable/RequestConfig.php @@ -8,6 +8,7 @@ */ namespace Piwik\ViewDataTable; +use Piwik\Common; /** @@ -346,6 +347,15 @@ class RequestConfig return $method; } + public function getRequestParam($paramName) + { + if (isset($this->request_parameters_to_modify[$paramName])) { + return $this->request_parameters_to_modify[$paramName]; + } + + return Common::getRequestVar($paramName, false); + } + /** * Override this method if you want to add custom request parameters to the API request based on ViewDataTable * parameters. Return in the result the list of extra parameters. diff --git a/plugins/CoreVisualizations/Visualizations/Cloud.php b/plugins/CoreVisualizations/Visualizations/Cloud.php index 1a199b327a..f5c5543116 100644 --- a/plugins/CoreVisualizations/Visualizations/Cloud.php +++ b/plugins/CoreVisualizations/Visualizations/Cloud.php @@ -47,6 +47,11 @@ class Cloud extends Visualization $this->config->show_limit_control = false; } + public function beforeLoadDataTable() + { + $this->checkRequestIsNotForMultiplePeriods(); + } + public function afterAllFiltersAreApplied() { if ($this->dataTable->getRowsCount() == 0) { diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable.php b/plugins/CoreVisualizations/Visualizations/HtmlTable.php index 522eed6ae5..2fa6e6674b 100644 --- a/plugins/CoreVisualizations/Visualizations/HtmlTable.php +++ b/plugins/CoreVisualizations/Visualizations/HtmlTable.php @@ -37,6 +37,11 @@ class HtmlTable extends Visualization return new HtmlTable\RequestConfig(); } + public function beforeLoadDataTable() + { + $this->checkRequestIsNotForMultiplePeriods(); + } + public function beforeRender() { if ($this->requestConfig->idSubtable diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php index 536477abb3..9f754eccc4 100644 --- a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php +++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php @@ -67,6 +67,8 @@ class AllColumns extends HtmlTable public function beforeLoadDataTable() { + parent::beforeLoadDataTable(); + unset($this->requestConfig->request_parameters_to_modify['pivotBy']); unset($this->requestConfig->request_parameters_to_modify['pivotByColumn']); } diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php index 1204ae8a09..122920da2d 100644 --- a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php +++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php @@ -25,6 +25,8 @@ class Bar extends JqplotGraph { parent::beforeLoadDataTable(); + $this->checkRequestIsNotForMultiplePeriods(); + $this->config->datatable_js_type = 'JqplotBarGraphDataTable'; } diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php index ae8e260bc1..ec6d4924cf 100644 --- a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php +++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php @@ -35,6 +35,8 @@ class Evolution extends JqplotGraph { parent::beforeRender(); + $this->checkRequestIsOnlyForMultiplePeriods(); + $this->config->show_flatten_table = false; $this->config->datatable_js_type = 'JqplotEvolutionGraphDataTable'; } diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php index 42ba69ef3f..32a2f2dfed 100644 --- a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php +++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php @@ -34,6 +34,8 @@ class Pie extends JqplotGraph { parent::beforeRender(); + $this->checkRequestIsNotForMultiplePeriods(); + $this->config->show_all_ticks = true; $this->config->datatable_js_type = 'JqplotPieGraphDataTable'; } diff --git a/plugins/ScheduledReports/API.php b/plugins/ScheduledReports/API.php index ab82b56b7e..7cdb0505a7 100644 --- a/plugins/ScheduledReports/API.php +++ b/plugins/ScheduledReports/API.php @@ -21,6 +21,7 @@ use Piwik\Filesystem; use Piwik\Http; use Piwik\Log; use Piwik\NoAccessException; +use Piwik\Period; use Piwik\Piwik; use Piwik\Plugins\ImageGraph\ImageGraph; use Piwik\Plugins\LanguagesManager\LanguagesManager; @@ -309,7 +310,7 @@ class API extends \Piwik\Plugin\API * @param string $date YYYY-MM-DD * @param bool|false|string $language If not passed, will use default language. * @param bool|false|int $outputType 1 = download report, 3 = output report in browser, 4 = return report content to caller, defaults to download - * @param bool|false|string $period Defaults to 'day'. If not specified, will default to the report's period set when creating the report + * @param bool|false|string $period If not specified, will default to the report's period set when creating the report * @param bool|false|string $reportFormat 'pdf', 'html' or any other format provided via the ScheduledReports.getReportFormats hook * @param bool|false|array $parameters array of parameters * @return array|void @@ -345,6 +346,8 @@ class API extends \Piwik\Plugin\API $period = $report['period_param']; } + $this->checkSinglePeriod($period, $date); + // override report format if (!empty($reportFormat)) { self::validateReportFormat($reportType, $reportFormat); @@ -1032,4 +1035,11 @@ class API extends \Piwik\Plugin\API throw new NoAccessException(Piwik::translate('General_ExceptionPrivilege', array("'view'"))); } } + + private function checkSinglePeriod($period, $date) + { + if (Period::isMultiplePeriod($date, $period)) { + throw new Http\BadRequestException("This API method does not support multiple periods."); + } + } } diff --git a/plugins/ScheduledReports/tests/Integration/ApiTest.php b/plugins/ScheduledReports/tests/Integration/ApiTest.php index 247b2136da..e445d99270 100644 --- a/plugins/ScheduledReports/tests/Integration/ApiTest.php +++ b/plugins/ScheduledReports/tests/Integration/ApiTest.php @@ -12,6 +12,7 @@ use Piwik\API\Proxy; use Piwik\Container\StaticContainer; use Piwik\DataTable; use Piwik\Date; +use Piwik\Http\BadRequestException; use Piwik\Plugins\MobileMessaging\API as APIMobileMessaging; use Piwik\Plugins\MobileMessaging\MobileMessaging; use Piwik\Plugins\ScheduledReports\API as APIScheduledReports; @@ -490,6 +491,31 @@ class ApiTest extends IntegrationTestCase } /** + * @expectedException \Piwik\Http\BadRequestException + * @expectedExceptionMessage This API method does not support multiple periods. + */ + public function test_generateReport_throwsIfMultiplePeriodsRequested() + { + $idReport = APIScheduledReports::getInstance()->addReport( + 1, + '', + Schedule::PERIOD_DAY, + 0, + ScheduledReports::EMAIL_TYPE, + ReportRenderer::HTML_FORMAT, + array( + 'VisitsSummary_get', + 'UserCountry_getCountry', + 'Referrers_getWebsites', + ), + array(ScheduledReports::DISPLAY_FORMAT_PARAMETER => ScheduledReports::DISPLAY_FORMAT_TABLES_ONLY) + ); + + APIScheduledReports::getInstance()->generateReport($idReport, '2012-03-03,2012-03-23', + $language = false, $outputType = APIScheduledReports::OUTPUT_RETURN); + } + + /** * @expectedException \Exception * @expectedExceptionMessage Invalid evolutionPeriodFor value */ |