Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiosmosis <benaka@piwik.pro>2015-03-12 12:26:38 +0300
committerdiosmosis <benaka@piwik.pro>2015-03-12 12:26:38 +0300
commit54bd3f0f18b3ba9edde0823d7f06e0769e5abad7 (patch)
tree4cc4c26ff9558a8cbc0ccf6afb2cd7498a1a1996 /plugins
parent5197b1cd4ddd21e7c2ab4cfe2906dff92ac35734 (diff)
parent484935ce69c19e94d4b2a95aca33e75b0802abbe (diff)
Merge branch 'master' into 7181_isolated_archive_purging
Conflicts: plugins/SitesManager/SitesManager.php
Diffstat (limited to 'plugins')
-rw-r--r--plugins/API/API.php2
-rw-r--r--plugins/Actions/API.php77
-rw-r--r--plugins/Actions/DataTable/Filter/Actions.php53
-rw-r--r--plugins/Actions/Reports/Base.php8
-rw-r--r--plugins/CoreAdminHome/Controller.php8
-rw-r--r--plugins/CoreAdminHome/Model/DuplicateActionRemover.php2
-rw-r--r--plugins/CoreAdminHome/lang/en.json1
-rw-r--r--plugins/CoreAdminHome/templates/optOut.twig43
-rw-r--r--plugins/CoreHome/Columns/Metrics/CallableProcessedMetric.php47
-rw-r--r--plugins/CoreHome/Controller.php28
-rw-r--r--plugins/CoreHome/DataTableRowAction/RowEvolution.php1
-rw-r--r--plugins/CoreHome/Menu.php2
-rw-r--r--plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.less1
-rw-r--r--plugins/CorePluginsAdmin/MarketplaceApiClient.php2
-rw-r--r--plugins/CoreUpdater/Controller.php22
-rw-r--r--plugins/CoreVisualizations/CoreVisualizations.php21
-rw-r--r--plugins/CoreVisualizations/Visualizations/HtmlTable.php4
-rw-r--r--plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php36
-rw-r--r--plugins/CoreVisualizations/Visualizations/HtmlTable/RequestConfig.php8
m---------plugins/CustomAlerts0
-rw-r--r--plugins/CustomVariables/API.php31
-rw-r--r--plugins/CustomVariables/DataTable/Filter/CustomVariablesValuesFromNameId.php42
-rw-r--r--plugins/Events/API.php40
-rw-r--r--plugins/Events/DataTable/Filter/ReplaceEventNameNotSet.php39
-rw-r--r--plugins/ExampleUI/Controller.php1
-rw-r--r--plugins/Goals/Columns/Metrics/GoalSpecificProcessedMetric.php12
-rw-r--r--plugins/Installation/SystemCheck.php4
-rw-r--r--plugins/Installation/lang/en.json2
-rwxr-xr-xplugins/Installation/templates/_systemCheckSection.twig11
-rw-r--r--plugins/Live/API.php49
-rw-r--r--plugins/Live/Controller.php4
-rw-r--r--plugins/Live/Model.php113
-rw-r--r--plugins/Live/Reports/GetSimpleLastVisitCount.php3
-rw-r--r--plugins/Live/tests/System/APITest.php32
-rw-r--r--plugins/Login/lang/en.json2
-rw-r--r--plugins/Provider/Columns/Provider.php13
m---------plugins/QueuedTracking0
-rw-r--r--plugins/Referrers/API.php150
-rw-r--r--plugins/Referrers/DataTable/Filter/KeywordNotDefined.php25
-rw-r--r--plugins/Referrers/DataTable/Filter/KeywordsFromSearchEngineId.php61
-rw-r--r--plugins/Referrers/DataTable/Filter/SearchEnginesFromKeywordId.php63
-rw-r--r--plugins/Referrers/DataTable/Filter/UrlsForSocial.php49
-rw-r--r--plugins/Referrers/DataTable/Filter/UrlsFromWebsiteId.php46
-rw-r--r--plugins/Referrers/Reports/GetWebsites.php1
m---------plugins/SecurityInfo0
-rw-r--r--plugins/SitesManager/Controller.php17
-rw-r--r--plugins/SitesManager/SitesManager.php22
-rw-r--r--plugins/SitesManager/lang/en.json3
-rw-r--r--plugins/SitesManager/stylesheets/SitesManager.less19
-rw-r--r--plugins/SitesManager/templates/siteWithoutData.twig25
m---------plugins/TasksTimetable0
-rw-r--r--plugins/TestRunner/Aws/config.ini.php1
-rw-r--r--plugins/TestRunner/Commands/TestsRunOnAws.php11
-rw-r--r--plugins/TestRunner/Runner/Remote.php16
-rw-r--r--plugins/TestRunner/templates/travis.yml.twig16
m---------plugins/TreemapVisualization0
-rw-r--r--plugins/UserCountry/Columns/Country.php13
m---------plugins/VisitorGenerator0
58 files changed, 1022 insertions, 280 deletions
diff --git a/plugins/API/API.php b/plugins/API/API.php
index 2f5f21f4e9..06f04447e2 100644
--- a/plugins/API/API.php
+++ b/plugins/API/API.php
@@ -196,7 +196,7 @@ class API extends \Piwik\Plugin\API
'segment' => 'visitIp',
'acceptedValues' => '13.54.122.1. </code>Select IP ranges with notation: <code>visitIp>13.54.122.0;visitIp<13.54.122.255',
'sqlSegment' => 'log_visit.location_ip',
- 'sqlFilterValue' => array('Piwik\IP', 'P2N'),
+ 'sqlFilterValue' => array('Piwik\Network\IPUtils', 'stringToBinaryIP'),
'permission' => $isAuthenticatedWithViewAccess,
);
diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php
index 91f1d70c45..891400e122 100644
--- a/plugins/Actions/API.php
+++ b/plugins/Actions/API.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\Actions;
use Exception;
-use Piwik\API\Request;
use Piwik\Archive;
use Piwik\Common;
use Piwik\DataTable;
@@ -84,14 +83,17 @@ class API extends \Piwik\Plugin\API
* @param bool $expanded
* @param bool|int $idSubtable
* @param bool|int $depth
+ * @param bool|int $flat
*
* @return DataTable|DataTable\Map
*/
public function getPageUrls($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false,
- $depth = false)
+ $depth = false, $flat = false)
{
- $dataTable = $this->getDataTableFromArchive('Actions_actions_url', $idSite, $period, $date, $segment, $expanded, $idSubtable, $depth);
- $this->filterActionsDataTable($dataTable, $expanded);
+ $dataTable = Archive::createDataTableFromArchive('Actions_actions_url', $idSite, $period, $date, $segment, $expanded, $flat, $idSubtable, $depth);
+
+ $this->filterActionsDataTable($dataTable);
+
return $dataTable;
}
@@ -136,7 +138,7 @@ class API extends \Piwik\Plugin\API
{
// Keep only pages which are following site search
$dataTable->filter('ColumnCallbackDeleteRow', array(
- 'nb_hits_following_search',
+ PiwikMetrics::INDEX_PAGE_IS_FOLLOWING_SITE_SEARCH_NB_HITS,
function ($value) {
return $value <= 0;
}
@@ -167,17 +169,19 @@ class API extends \Piwik\Plugin\API
public function getPageUrl($pageUrl, $idSite, $period, $date, $segment = false)
{
- $callBackParameters = array('Actions_actions_url', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false);
+ $callBackParameters = array('Actions_actions_url', $idSite, $period, $date, $segment, $expanded = false, $flat = false, $idSubtable = null);
$dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $pageUrl, Action::TYPE_PAGE_URL);
$this->addPageProcessedMetrics($dataTable);
$this->filterActionsDataTable($dataTable);
return $dataTable;
}
- public function getPageTitles($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
+ public function getPageTitles($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false, $flat = false)
{
- $dataTable = $this->getDataTableFromArchive('Actions_actions', $idSite, $period, $date, $segment, $expanded, $idSubtable);
- $this->filterActionsDataTable($dataTable, $expanded);
+ $dataTable = Archive::createDataTableFromArchive('Actions_actions', $idSite, $period, $date, $segment, $expanded, $flat, $idSubtable);
+
+ $this->filterActionsDataTable($dataTable);
+
return $dataTable;
}
@@ -207,38 +211,38 @@ class API extends \Piwik\Plugin\API
public function getPageTitle($pageName, $idSite, $period, $date, $segment = false)
{
- $callBackParameters = array('Actions_actions', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false);
+ $callBackParameters = array('Actions_actions', $idSite, $period, $date, $segment, $expanded = false, $flat = false, $idSubtable = null);
$dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $pageName, Action::TYPE_PAGE_TITLE);
$this->addPageProcessedMetrics($dataTable);
$this->filterActionsDataTable($dataTable);
return $dataTable;
}
- public function getDownloads($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
+ public function getDownloads($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false, $flat = false)
{
- $dataTable = $this->getDataTableFromArchive('Actions_downloads', $idSite, $period, $date, $segment, $expanded, $idSubtable);
+ $dataTable = Archive::createDataTableFromArchive('Actions_downloads', $idSite, $period, $date, $segment, $expanded, $flat, $idSubtable);
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
}
public function getDownload($downloadUrl, $idSite, $period, $date, $segment = false)
{
- $callBackParameters = array('Actions_downloads', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false);
+ $callBackParameters = array('Actions_downloads', $idSite, $period, $date, $segment, $expanded = false, $flat = false, $idSubtable = null);
$dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $downloadUrl, Action::TYPE_DOWNLOAD);
$this->filterActionsDataTable($dataTable);
return $dataTable;
}
- public function getOutlinks($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
+ public function getOutlinks($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false, $flat = false)
{
- $dataTable = $this->getDataTableFromArchive('Actions_outlink', $idSite, $period, $date, $segment, $expanded, $idSubtable);
+ $dataTable = Archive::createDataTableFromArchive('Actions_outlink', $idSite, $period, $date, $segment, $expanded, $flat, $idSubtable);
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
}
public function getOutlink($outlinkUrl, $idSite, $period, $date, $segment = false)
{
- $callBackParameters = array('Actions_outlink', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false);
+ $callBackParameters = array('Actions_outlink', $idSite, $period, $date, $segment, $expanded = false, $flat = false, $idSubtable = null);
$dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $outlinkUrl, Action::TYPE_OUTLINK);
$this->filterActionsDataTable($dataTable);
return $dataTable;
@@ -249,6 +253,7 @@ class API extends \Piwik\Plugin\API
$dataTable = $this->getSiteSearchKeywordsRaw($idSite, $period, $date, $segment);
$dataTable->deleteColumn(PiwikMetrics::INDEX_SITE_SEARCH_HAS_NO_RESULT);
$this->filterActionsDataTable($dataTable);
+ $dataTable->filter('ReplaceColumnNames');
$this->addPagesPerSearchColumn($dataTable);
return $dataTable;
}
@@ -266,7 +271,7 @@ class API extends \Piwik\Plugin\API
protected function getSiteSearchKeywordsRaw($idSite, $period, $date, $segment)
{
- $dataTable = $this->getDataTableFromArchive('Actions_sitesearch', $idSite, $period, $date, $segment, $expanded = false);
+ $dataTable = Archive::createDataTableFromArchive('Actions_sitesearch', $idSite, $period, $date, $segment, $expanded = false);
return $dataTable;
}
@@ -284,6 +289,7 @@ class API extends \Piwik\Plugin\API
$dataTable->deleteRow(DataTable::ID_SUMMARY_ROW);
$dataTable->deleteColumn(PiwikMetrics::INDEX_SITE_SEARCH_HAS_NO_RESULT);
$this->filterActionsDataTable($dataTable);
+ $dataTable->filter('ReplaceColumnNames');
$this->addPagesPerSearchColumn($dataTable);
return $dataTable;
}
@@ -332,6 +338,7 @@ class API extends \Piwik\Plugin\API
}
}
$this->filterActionsDataTable($dataTable);
+ $dataTable->filter('ReplaceColumnNames');
$this->addPagesPerSearchColumn($dataTable, $columnToRead = 'nb_actions');
return $dataTable;
}
@@ -361,7 +368,7 @@ class API extends \Piwik\Plugin\API
if ($table === false) {
// fetch the data table
- $table = call_user_func_array(array($this, 'getDataTableFromArchive'), $callBackParameters);
+ $table = call_user_func_array('\Piwik\Archive::createDataTableFromArchive', $callBackParameters);
if ($table instanceof DataTable\Map) {
// search an array of tables, e.g. when using date=last30
@@ -416,7 +423,7 @@ class API extends \Piwik\Plugin\API
// end of tree search reached
if (count($searchTree) == 0) {
- $result = new DataTable();
+ $result = $table->getEmptyClone();
$result->addRow($row);
$result->setAllTableMetadata($table->getAllTableMetadata());
return $result;
@@ -424,7 +431,7 @@ class API extends \Piwik\Plugin\API
// match found on this level and more levels remaining: go deeper
$idSubTable = $row->getIdSubDataTable();
- $callBackParameters[6] = $idSubTable;
+ $callBackParameters[7] = $idSubTable;
/**
* @var \Piwik\Period $period
@@ -434,7 +441,7 @@ class API extends \Piwik\Plugin\API
$callBackParameters[3] = $period->getDateStart() . ',' . $period->getDateEnd();
}
- $table = call_user_func_array(array($this, 'getDataTableFromArchive'), $callBackParameters);
+ $table = call_user_func_array('\Piwik\Archive::createDataTableFromArchive', $callBackParameters);
return $this->doFilterPageDatatableSearch($callBackParameters, $table, $searchTree);
}
@@ -445,28 +452,15 @@ class API extends \Piwik\Plugin\API
* Common filters for all Actions API
*
* @param DataTable|DataTable\Simple|DataTable\Map $dataTable
- * @param bool $expanded
*/
- protected function filterActionsDataTable($dataTable, $expanded = false)
+ private function filterActionsDataTable($dataTable)
{
// Must be applied before Sort in this case, since the DataTable can contain both int and strings indexes
// (in the transition period between pre 1.2 and post 1.2 datatable structure)
- $dataTable->filter('ReplaceColumnNames');
- $dataTable->filter('Sort', array('nb_visits', 'desc', $naturalSort = false, $expanded));
- $dataTable->filter(function (DataTable $dataTable) {
- foreach ($dataTable->getRows() as $row) {
- $url = $row->getMetadata('url');
- if ($url) {
- $row->setMetadata('segmentValue', urldecode($url));
- }
- }
- });
- $dataTable->filter('GroupBy', array('label', function ($label) {
- return urldecode($label);
- }));
+ $dataTable->filter('Piwik\Plugins\Actions\DataTable\Filter\Actions');
- $dataTable->queueFilter('ReplaceSummaryRowLabel');
+ return $dataTable;
}
/**
@@ -477,7 +471,7 @@ class API extends \Piwik\Plugin\API
private function filterNonEntryActions($dataTable)
{
$dataTable->filter('ColumnCallbackDeleteRow',
- array('entry_nb_visits',
+ array(PiwikMetrics::INDEX_PAGE_ENTRY_NB_VISITS,
function ($visits) {
return !strlen($visits);
}
@@ -493,18 +487,13 @@ class API extends \Piwik\Plugin\API
private function filterNonExitActions($dataTable)
{
$dataTable->filter('ColumnCallbackDeleteRow',
- array('exit_nb_visits',
+ array(PiwikMetrics::INDEX_PAGE_EXIT_NB_VISITS,
function ($visits) {
return !strlen($visits);
})
);
}
- protected function getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded = false, $idSubtable = null, $depth = null)
- {
- return Archive::getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded, $idSubtable, $depth);
- }
-
private function addPageProcessedMetrics(DataTable\DataTableInterface $dataTable)
{
$dataTable->filter(function (DataTable $table) {
diff --git a/plugins/Actions/DataTable/Filter/Actions.php b/plugins/Actions/DataTable/Filter/Actions.php
new file mode 100644
index 0000000000..71abe4190b
--- /dev/null
+++ b/plugins/Actions/DataTable/Filter/Actions.php
@@ -0,0 +1,53 @@
+<?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\Actions\DataTable\Filter;
+
+use Piwik\DataTable\BaseFilter;
+use Piwik\DataTable\Row;
+use Piwik\DataTable;
+
+class Actions extends BaseFilter
+{
+ /**
+ * Constructor.
+ *
+ * @param DataTable $table The table to eventually filter.
+ */
+ public function __construct($table)
+ {
+ parent::__construct($table);
+ }
+
+ /**
+ * @param DataTable $table
+ */
+ public function filter($table)
+ {
+ $table->filter(function (DataTable $dataTable) {
+ foreach ($dataTable->getRows() as $row) {
+ $url = $row->getMetadata('url');
+ if ($url) {
+ $row->setMetadata('segmentValue', urldecode($url));
+ }
+ }
+ });
+
+ // TODO can we remove this one again?
+ $table->queueFilter('GroupBy', array('label', function ($label) {
+ return urldecode($label);
+ }));
+
+ foreach ($table->getRows() as $row) {
+ $subtable = $row->getSubtable();
+ if ($subtable) {
+ $this->filter($subtable);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/Actions/Reports/Base.php b/plugins/Actions/Reports/Base.php
index 68bca741a3..45c9c0af9c 100644
--- a/plugins/Actions/Reports/Base.php
+++ b/plugins/Actions/Reports/Base.php
@@ -9,6 +9,7 @@
namespace Piwik\Plugins\Actions\Reports;
use Piwik\Common;
+use Piwik\Metrics;
use Piwik\Metrics\Formatter;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
@@ -22,6 +23,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
$this->category = 'General_Actions';
$this->processedMetrics = false;
+ $this->recursiveLabelSeparator = '/';
}
protected function addBaseDisplayProperties(ViewDataTable $view)
@@ -90,7 +92,11 @@ abstract class Base extends \Piwik\Plugin\Report
protected function addExcludeLowPopDisplayProperties(ViewDataTable $view)
{
if (Common::getRequestVar('enable_filter_excludelowpop', '0', 'string') != '0') {
- $view->requestConfig->filter_excludelowpop = 'nb_hits';
+ if (Common::getRequestVar('flat', 0, 'int') === 1) {
+ $view->requestConfig->filter_excludelowpop = 'nb_hits';
+ } else {
+ $view->requestConfig->filter_excludelowpop = Metrics::INDEX_PAGE_NB_HITS;
+ }
$view->requestConfig->filter_excludelowpop_value = function () {
// computing minimum value to exclude (2 percent of the total number of actions)
$visitsInfo = \Piwik\Plugins\VisitsSummary\Controller::getVisitsSummary()->getFirstRow();
diff --git a/plugins/CoreAdminHome/Controller.php b/plugins/CoreAdminHome/Controller.php
index 732639874a..eacbb60406 100644
--- a/plugins/CoreAdminHome/Controller.php
+++ b/plugins/CoreAdminHome/Controller.php
@@ -321,7 +321,10 @@ class Controller extends ControllerAdmin
public function optOut()
{
$trackVisits = !IgnoreCookie::isIgnoreCookieFound();
-
+
+ $dntChecker = new DoNotTrackHeaderChecker();
+ $dntFound = $dntChecker->isDoNotTrackFound();
+
$nonce = Common::getRequestVar('nonce', false);
$language = Common::getRequestVar('language', '');
if ($nonce !== false && Nonce::verifyNonce('Piwik_OptOut', $nonce)) {
@@ -330,6 +333,8 @@ class Controller extends ControllerAdmin
$trackVisits = !$trackVisits;
}
+
+
$lang = APILanguagesManager::getInstance()->isLanguageAvailable($language)
? $language
: LanguagesManager::getLanguageCodeForCurrentUser();
@@ -339,6 +344,7 @@ class Controller extends ControllerAdmin
// parameter is required)
$view = new View("@CoreAdminHome/optOut");
$view->setXFrameOptions('allow');
+ $view->dntFound = $dntFound;
$view->trackVisits = $trackVisits;
$view->nonce = Nonce::getNonce('Piwik_OptOut', 3600);
$view->language = $lang;
diff --git a/plugins/CoreAdminHome/Model/DuplicateActionRemover.php b/plugins/CoreAdminHome/Model/DuplicateActionRemover.php
index 21a5613616..bd3f143b09 100644
--- a/plugins/CoreAdminHome/Model/DuplicateActionRemover.php
+++ b/plugins/CoreAdminHome/Model/DuplicateActionRemover.php
@@ -56,7 +56,7 @@ class DuplicateActionRemover
* @param TableMetadata $tableMetadataAccess
* @param LoggerInterface $logger
*/
- public function __construct($tableMetadataAccess = null, $logger = null)
+ public function __construct(TableMetadata $tableMetadataAccess = null, LoggerInterface $logger = null)
{
$this->tableMetadataAccess = $tableMetadataAccess ?: new TableMetadata();
$this->logger = $logger ?: StaticContainer::get('Psr\Log\LoggerInterface');
diff --git a/plugins/CoreAdminHome/lang/en.json b/plugins/CoreAdminHome/lang/en.json
index 42c0ae3960..9579bdd518 100644
--- a/plugins/CoreAdminHome/lang/en.json
+++ b/plugins/CoreAdminHome/lang/en.json
@@ -59,6 +59,7 @@
"MenuDevelopment": "Development",
"OptOutComplete": "Opt-out complete; your visits to this website will not be recorded by the Web Analytics tool.",
"OptOutCompleteBis": "Note that if you clear your cookies, delete the opt-out cookie, or if you change computers or Web browsers, you will need to perform the opt-out procedure again.",
+ "OptOutDntFound": "You are not being tracked since your browser is reporting that you do not want to. This is a setting of your browser so you won't be able to opt-in until you disable the 'Do Not Track' feature.",
"OptOutExplanation": "Piwik is dedicated to providing privacy on the Internet. To provide your visitors with the choice of opting-out of Piwik Web Analytics, you can add the following HTML code on one of your website page, for example in a Privacy Policy page.",
"OptOutExplanationBis": "This code will display an Iframe containing a link for your visitors to opt-out of Piwik by setting an opt-out cookie in their browsers. %s Click here%s to view the content that will be displayed by the iFrame.",
"OptOutForYourVisitors": "Piwik opt-out for your visitors",
diff --git a/plugins/CoreAdminHome/templates/optOut.twig b/plugins/CoreAdminHome/templates/optOut.twig
index e9af0948c1..5315747a48 100644
--- a/plugins/CoreAdminHome/templates/optOut.twig
+++ b/plugins/CoreAdminHome/templates/optOut.twig
@@ -4,31 +4,34 @@
<meta charset="utf-8">
</head>
<body>
-{% if not trackVisits %}
- {{ 'CoreAdminHome_OptOutComplete'|translate }}
- <br/>
- {{ 'CoreAdminHome_OptOutCompleteBis'|translate }}
+{% if dntFound %}
+ {{ 'CoreAdminHome_OptOutDntFound'|translate }}
{% else %}
- {{ 'CoreAdminHome_YouMayOptOut'|translate }}
- <br/>
- {{ 'CoreAdminHome_YouMayOptOutBis'|translate }}
-{% endif %}
-<br/><br/>
-
-<form method="post" action="?module=CoreAdminHome&amp;action=optOut{% if language %}&amp;language={{ language }}{% endif %}">
- <input type="hidden" name="nonce" value="{{ nonce }}" />
- <input type="hidden" name="fuzz" value="{{ "now"|date }}" />
- <input onclick="this.form.submit()" type="checkbox" id="trackVisits" name="trackVisits" {% if trackVisits %}checked="checked"{% endif %} />
- <label for="trackVisits"><strong>
+ {% if not trackVisits %}
+ {{ 'CoreAdminHome_OptOutComplete'|translate }}
+ <br/>
+ {{ 'CoreAdminHome_OptOutCompleteBis'|translate }}
+ {% else %}
+ {{ 'CoreAdminHome_YouMayOptOut'|translate }}
+ <br/>
+ {{ 'CoreAdminHome_YouMayOptOutBis'|translate }}
+ {% endif %}
+ <br/><br/>
+ <form method="post" action="?module=CoreAdminHome&amp;action=optOut{% if language %}&amp;language={{ language }}{% endif %}">
+ <input type="hidden" name="nonce" value="{{ nonce }}" />
+ <input type="hidden" name="fuzz" value="{{ "now"|date }}" />
+ <input onclick="this.form.submit()" type="checkbox" id="trackVisits" name="trackVisits" {% if trackVisits %}checked="checked"{% endif %} />
+ <label for="trackVisits"><strong>
{% if trackVisits %}
{{ 'CoreAdminHome_YouAreOptedIn'|translate }} {{ 'CoreAdminHome_ClickHereToOptOut'|translate }}
{% else %}
{{ 'CoreAdminHome_YouAreOptedOut'|translate }} {{ 'CoreAdminHome_ClickHereToOptIn'|translate }}
{% endif %}
- </strong></label>
- <noscript>
- <button type="submit">{{ 'General_Save'|translate }}</button>
- </noscript>
-</form>
+ </strong></label>
+ <noscript>
+ <button type="submit">{{ 'General_Save'|translate }}</button>
+ </noscript>
+ </form>
+{% endif %}
</body>
</html>
diff --git a/plugins/CoreHome/Columns/Metrics/CallableProcessedMetric.php b/plugins/CoreHome/Columns/Metrics/CallableProcessedMetric.php
new file mode 100644
index 0000000000..646c48e862
--- /dev/null
+++ b/plugins/CoreHome/Columns/Metrics/CallableProcessedMetric.php
@@ -0,0 +1,47 @@
+<?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\CoreHome\Columns\Metrics;
+
+use Piwik\DataTable\Row;
+use Piwik\Plugin\ProcessedMetric;
+
+class CallableProcessedMetric extends ProcessedMetric
+{
+ private $name;
+ private $callback;
+ private $dependentMetrics;
+
+ public function __construct($name, $callback, $dependentMetrics = array())
+ {
+ $this->name = $name;
+ $this->callback = $callback;
+ $this->dependentMetrics = $dependentMetrics;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function compute(Row $row)
+ {
+ if ($this->callback) {
+ return call_user_func($this->callback, $row);
+ }
+ }
+
+ public function getTranslatedName()
+ {
+ return '';
+ }
+
+ public function getDependentMetrics()
+ {
+ return $this->dependentMetrics;
+ }
+} \ No newline at end of file
diff --git a/plugins/CoreHome/Controller.php b/plugins/CoreHome/Controller.php
index 7fdfe1d814..38474e5bb7 100644
--- a/plugins/CoreHome/Controller.php
+++ b/plugins/CoreHome/Controller.php
@@ -49,17 +49,11 @@ class Controller extends \Piwik\Plugin\Controller
return 'redirectToCoreHomeIndex';
}
- public function renderReportMenu($reportModule = null, $reportAction = null)
+ public function renderReportMenu(Report $report)
{
Piwik::checkUserHasSomeViewAccess();
$this->checkSitePermission();
- $report = Report::factory($reportModule, $reportAction);
-
- if (empty($report)) {
- throw new Exception($this->translator->translate('General_ExceptionReportNotFound'));
- }
-
$report->checkIsEnabled();
$menuTitle = $report->getMenuTitle();
@@ -69,38 +63,26 @@ class Controller extends \Piwik\Plugin\Controller
}
$menuTitle = $this->translator->translate($menuTitle);
- $content = $this->renderReportWidget($reportModule, $reportAction);
+ $content = $this->renderReportWidget($report);
return View::singleReport($menuTitle, $content);
}
- public function renderReportWidget($reportModule = null, $reportAction = null)
+ public function renderReportWidget(Report $report)
{
Piwik::checkUserHasSomeViewAccess();
$this->checkSitePermission();
- $report = Report::factory($reportModule, $reportAction);
-
- if (empty($report)) {
- throw new Exception($this->translator->translate('General_ExceptionReportNotFound'));
- }
-
$report->checkIsEnabled();
return $report->render();
}
- public function renderWidget($widgetModule = null, $widgetAction = null)
+ public function renderWidget(PluginWidgets $widget, $method)
{
Piwik::checkUserHasSomeViewAccess();
- $widget = PluginWidgets::factory($widgetModule, $widgetAction);
-
- if (!empty($widget)) {
- return $widget->$widgetAction();
- }
-
- throw new Exception($this->translator->translate('General_ExceptionWidgetNotFound'));
+ return $widget->$method();
}
function redirectToCoreHomeIndex()
diff --git a/plugins/CoreHome/DataTableRowAction/RowEvolution.php b/plugins/CoreHome/DataTableRowAction/RowEvolution.php
index e1bc8d5d4f..85fa98bc3e 100644
--- a/plugins/CoreHome/DataTableRowAction/RowEvolution.php
+++ b/plugins/CoreHome/DataTableRowAction/RowEvolution.php
@@ -198,6 +198,7 @@ class RowEvolution
$view->config->columns_to_display = array_keys($metrics ? : $this->graphMetrics);
}
+ $view->requestConfig->request_parameters_to_modify['label'] = '';
$view->config->show_goals = false;
$view->config->show_search = false;
$view->config->show_all_views_icons = false;
diff --git a/plugins/CoreHome/Menu.php b/plugins/CoreHome/Menu.php
index b2c239885e..f63dc76eec 100644
--- a/plugins/CoreHome/Menu.php
+++ b/plugins/CoreHome/Menu.php
@@ -38,7 +38,7 @@ class Menu extends \Piwik\Plugin\Menu
$module = $this->getLoginModule();
if (Piwik::isUserIsAnonymous()) {
- $menu->addItem('Login_LogIn', null, array('module' => $module), 999);
+ $menu->addItem('Login_LogIn', null, array('module' => $module, 'action' => false), 999);
} else {
$menu->addItem('General_Logout', null, array('module' => $module, 'action' => 'logout', 'idSite' => null), 999);
}
diff --git a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.less b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.less
index a2155872e4..da8b79a1fc 100644
--- a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.less
+++ b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.less
@@ -15,7 +15,6 @@
right: -15px;
color: @theme-color-link;
display: inline;
- content: " \25BC";
font-size: 1px;
height: 0px;
width: 0px;
diff --git a/plugins/CorePluginsAdmin/MarketplaceApiClient.php b/plugins/CorePluginsAdmin/MarketplaceApiClient.php
index 6472da3dea..37020ef8cd 100644
--- a/plugins/CorePluginsAdmin/MarketplaceApiClient.php
+++ b/plugins/CorePluginsAdmin/MarketplaceApiClient.php
@@ -18,7 +18,7 @@ use Piwik\Version;
class MarketplaceApiClient
{
const CACHE_TIMEOUT_IN_SECONDS = 1200;
- const HTTP_REQUEST_TIMEOUT = 3;
+ const HTTP_REQUEST_TIMEOUT = 10;
private $domain = 'http://plugins.piwik.org';
diff --git a/plugins/CoreUpdater/Controller.php b/plugins/CoreUpdater/Controller.php
index 90b0d13aa5..c8f3e927b5 100644
--- a/plugins/CoreUpdater/Controller.php
+++ b/plugins/CoreUpdater/Controller.php
@@ -37,6 +37,8 @@ use Piwik\View;
class Controller extends \Piwik\Plugin\Controller
{
const PATH_TO_EXTRACT_LATEST_VERSION = '/latest/';
+ const LATEST_VERSION_URL = '://builds.piwik.org/piwik.zip';
+ const LATEST_BETA_VERSION_URL = '://builds.piwik.org/piwik-%s.zip';
private $coreError = false;
private $warningMessages = array();
@@ -48,9 +50,18 @@ class Controller extends \Piwik\Plugin\Controller
protected static function getLatestZipUrl($newVersion)
{
if (@Config::getInstance()->Debug['allow_upgrades_to_beta']) {
- return 'http://builds.piwik.org/piwik-' . $newVersion . '.zip';
+ $url = sprintf(self::LATEST_BETA_VERSION_URL, $newVersion);
+ } else {
+ $url = self::LATEST_VERSION_URL;
+ }
+
+ if (self::isUpdatingOverHttps()) {
+ $url = 'https' . $url;
+ } else {
+ $url = 'http' . $url;
}
- return Config::getInstance()->General['latest_version_url'];
+
+ return $url;
}
public function newVersionAvailable()
@@ -426,4 +437,11 @@ class Controller extends \Piwik\Plugin\Controller
return PluginManager::getInstance()->getIncompatiblePlugins($piwikVersion);
}
+ public static function isUpdatingOverHttps()
+ {
+ $openSslEnabled = extension_loaded('openssl');
+ $usingMethodSupportingHttps = (Http::getTransportMethod() !== 'socket');
+
+ return $openSslEnabled && $usingMethodSupportingHttps;
+ }
}
diff --git a/plugins/CoreVisualizations/CoreVisualizations.php b/plugins/CoreVisualizations/CoreVisualizations.php
index 54aa127c91..da8fbe9f94 100644
--- a/plugins/CoreVisualizations/CoreVisualizations.php
+++ b/plugins/CoreVisualizations/CoreVisualizations.php
@@ -9,6 +9,7 @@
namespace Piwik\Plugins\CoreVisualizations;
+use Piwik\Common;
use Piwik\ViewDataTable\Manager as ViewDataTableManager;
require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/JqplotDataGenerator.php';
@@ -28,7 +29,8 @@ class CoreVisualizations extends \Piwik\Plugin
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
- 'UsersManager.deleteUser' => 'deleteUser'
+ 'UsersManager.deleteUser' => 'deleteUser',
+ 'ViewDataTable.addViewDataTable' => 'addViewDataTable'
);
}
@@ -37,6 +39,23 @@ class CoreVisualizations extends \Piwik\Plugin
ViewDataTableManager::clearUserViewDataTableParameters($userLogin);
}
+ public function addViewDataTable(&$viewDataTable)
+ {
+ // Both are the same HtmlTable, just the Pivot one has some extra logic in case Pivot is used.
+ // We don't want to use the same HtmlTable twice in the UI. Therefore we always need to remove one.
+ if (Common::getRequestVar('pivotBy', '')) {
+ $tableToRemove = 'Visualizations\HtmlTable';
+ } else {
+ $tableToRemove = 'HtmlTable\PivotBy';
+ }
+
+ foreach ($viewDataTable as $index => $table) {
+ if (Common::stringEndsWith($table, $tableToRemove)) {
+ unset($viewDataTable[$index]);
+ }
+ }
+ }
+
public function getStylesheetFiles(&$stylesheets)
{
$stylesheets[] = "plugins/CoreVisualizations/stylesheets/dataTableVisualizations.less";
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable.php b/plugins/CoreVisualizations/Visualizations/HtmlTable.php
index dcd2374df9..66cb4c26e9 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable.php
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable.php
@@ -70,10 +70,6 @@ class HtmlTable extends Visualization
$dataTable = $request->process();
$this->assignTemplateVar('siteSummary', $dataTable);
}
-
- if ($this->requestConfig->pivotBy) {
- $this->config->columns_to_display = $this->dataTable->getColumns();
- }
}
}
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php
new file mode 100644
index 0000000000..1703988599
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php
@@ -0,0 +1,36 @@
+<?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\CoreVisualizations\Visualizations\HtmlTable;
+
+use Piwik\DataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+use Piwik\View;
+
+/**
+ * DataTable Visualization that derives from HtmlTable and sets show_extra_columns to true.
+ */
+class PivotBy extends HtmlTable
+{
+ public function beforeGenericFiltersAreAppliedToLoadedDataTable()
+ {
+ $this->config->columns_to_display = $this->dataTable->getColumns();
+
+ $this->dataTable->applyQueuedFilters();
+
+ parent::beforeGenericFiltersAreAppliedToLoadedDataTable();
+ }
+
+ public function beforeRender()
+ {
+ parent::beforeRender();
+
+ $this->config->columns_to_display = $this->dataTable->getColumns();
+ }
+}
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/RequestConfig.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/RequestConfig.php
index c507d1857e..2f674a5872 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable/RequestConfig.php
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/RequestConfig.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
use Piwik\Common;
use Piwik\Config as PiwikConfig;
+use Piwik\Metrics;
use Piwik\ViewDataTable\RequestConfig as VisualizationRequestConfig;
/**
@@ -33,7 +34,12 @@ class RequestConfig extends VisualizationRequestConfig
$this->filter_limit = PiwikConfig::getInstance()->General['datatable_default_limit'];
if (Common::getRequestVar('enable_filter_excludelowpop', false) == '1') {
- $this->filter_excludelowpop = 'nb_visits';
+ if (Common::getRequestVar('flat', 0, 'int') === 1) {
+ $this->filter_excludelowpop = 'nb_visits';
+ } else {
+ $this->filter_excludelowpop = Metrics::INDEX_NB_VISITS;
+ }
+
$this->filter_excludelowpop_value = false;
}
diff --git a/plugins/CustomAlerts b/plugins/CustomAlerts
-Subproject 40db402aeacae2d911331ec94df5d86df6f8713
+Subproject 628d2086db2742a29f39173c8be2fd348a64c6a
diff --git a/plugins/CustomVariables/API.php b/plugins/CustomVariables/API.php
index 727ef7d42c..1a6fc8c794 100644
--- a/plugins/CustomVariables/API.php
+++ b/plugins/CustomVariables/API.php
@@ -12,7 +12,6 @@ use Piwik\Archive;
use Piwik\DataTable;
use Piwik\Date;
use Piwik\Metrics;
-use Piwik\Piwik;
use Piwik\Plugins\Actions\Actions\ActionSiteSearch;
/**
@@ -32,12 +31,17 @@ class API extends \Piwik\Plugin\API
*
* @return DataTable|DataTable\Map
*/
- protected function getDataTable($idSite, $period, $date, $segment, $expanded, $idSubtable)
+ protected function getDataTable($idSite, $period, $date, $segment, $expanded, $flat, $idSubtable)
{
- $dataTable = Archive::getDataTableFromArchive(Archiver::CUSTOM_VARIABLE_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $idSubtable);
+ $dataTable = Archive::createDataTableFromArchive(Archiver::CUSTOM_VARIABLE_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $flat, $idSubtable);
$dataTable->filter('Sort', array(Metrics::INDEX_NB_ACTIONS, 'desc', $naturalSort = false, $expanded));
- $dataTable->queueFilter('ReplaceColumnNames');
$dataTable->queueFilter('ColumnDelete', 'nb_uniq_visitors');
+
+ if ($flat) {
+ $dataTable->filterSubtables('Sort', array(Metrics::INDEX_NB_ACTIONS, 'desc', $naturalSort = false, $expanded));
+ $dataTable->queueFilterSubtables('ColumnDelete', 'nb_uniq_visitors');
+ }
+
return $dataTable;
}
@@ -48,12 +52,13 @@ class API extends \Piwik\Plugin\API
* @param string|bool $segment
* @param bool $expanded
* @param bool $_leavePiwikCoreVariables
+ * @param bool $flat
*
* @return DataTable|DataTable\Map
*/
- public function getCustomVariables($idSite, $period, $date, $segment = false, $expanded = false, $_leavePiwikCoreVariables = false)
+ public function getCustomVariables($idSite, $period, $date, $segment = false, $expanded = false, $_leavePiwikCoreVariables = false, $flat = false)
{
- $dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded, $idSubtable = null);
+ $dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded, $flat, $idSubtable = null);
if ($dataTable instanceof DataTable
&& !$_leavePiwikCoreVariables
@@ -66,6 +71,11 @@ class API extends \Piwik\Plugin\API
}
}
}
+
+ if ($flat) {
+ $dataTable->filterSubtables('Piwik\Plugins\CustomVariables\DataTable\Filter\CustomVariablesValuesFromNameId');
+ }
+
return $dataTable;
}
@@ -90,7 +100,7 @@ class API extends \Piwik\Plugin\API
*/
public function getCustomVariablesValuesFromNameId($idSite, $period, $date, $idSubtable, $segment = false, $_leavePriceViewedColumn = false)
{
- $dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded = false, $idSubtable);
+ $dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded = false, $flat = false, $idSubtable);
if (!$_leavePriceViewedColumn) {
$dataTable->deleteColumn('price_viewed');
@@ -98,11 +108,8 @@ class API extends \Piwik\Plugin\API
// Hack Ecommerce product price tracking to display correctly
$dataTable->renameColumn('price_viewed', 'price');
}
- $dataTable->queueFilter('ColumnCallbackReplace', array('label', function ($label) {
- return $label == \Piwik\Plugins\CustomVariables\Archiver::LABEL_CUSTOM_VALUE_NOT_DEFINED
- ? Piwik::translate('General_NotDefined', Piwik::translate('CustomVariables_ColumnCustomVariableValue'))
- : $label;
- }));
+ $dataTable->filter('Piwik\Plugins\CustomVariables\DataTable\Filter\CustomVariablesValuesFromNameId');
+
return $dataTable;
}
}
diff --git a/plugins/CustomVariables/DataTable/Filter/CustomVariablesValuesFromNameId.php b/plugins/CustomVariables/DataTable/Filter/CustomVariablesValuesFromNameId.php
new file mode 100644
index 0000000000..4bab2f290e
--- /dev/null
+++ b/plugins/CustomVariables/DataTable/Filter/CustomVariablesValuesFromNameId.php
@@ -0,0 +1,42 @@
+<?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\CustomVariables\DataTable\Filter;
+
+use Piwik\DataTable\BaseFilter;
+use Piwik\DataTable\Row;
+use Piwik\DataTable;
+use Piwik\Piwik;
+
+class CustomVariablesValuesFromNameId extends BaseFilter
+{
+
+ /**
+ * Constructor.
+ *
+ * @param DataTable $table The table to eventually filter.
+ */
+ public function __construct($table)
+ {
+ parent::__construct($table);
+ }
+
+ /**
+ * @param DataTable $table
+ */
+ public function filter($table)
+ {
+ $notDefinedLabel = Piwik::translate('General_NotDefined', Piwik::translate('CustomVariables_ColumnCustomVariableValue'));
+
+ $table->queueFilter('ColumnCallbackReplace', array('label', function ($label) use ($notDefinedLabel) {
+ return $label == \Piwik\Plugins\CustomVariables\Archiver::LABEL_CUSTOM_VALUE_NOT_DEFINED
+ ? $notDefinedLabel
+ : $label;
+ }));
+ }
+} \ No newline at end of file
diff --git a/plugins/Events/API.php b/plugins/Events/API.php
index bb6584b777..7950cd2637 100644
--- a/plugins/Events/API.php
+++ b/plugins/Events/API.php
@@ -148,14 +148,17 @@ class API extends \Piwik\Plugin\API
}
}
- protected function getDataTable($name, $idSite, $period, $date, $segment, $expanded = false, $idSubtable = null, $secondaryDimension = false)
+ protected function getDataTable($name, $idSite, $period, $date, $segment, $expanded = false, $idSubtable = null, $secondaryDimension = false, $flat = false)
{
Piwik::checkUserHasViewAccess($idSite);
$this->checkSecondaryDimension($name, $secondaryDimension);
$recordName = $this->getRecordNameForAction($name, $secondaryDimension);
- $dataTable = Archive::getDataTableFromArchive($recordName, $idSite, $period, $date, $segment, $expanded, $idSubtable);
- if (empty($idSubtable)) {
+ $dataTable = Archive::createDataTableFromArchive($recordName, $idSite, $period, $date, $segment, $expanded, $flat, $idSubtable);
+
+ if ($flat) {
+ $dataTable->filterSubtables('Piwik\Plugins\Events\DataTable\Filter\ReplaceEventNameNotSet');
+ } else {
$dataTable->filter('AddSegmentValue', array(function ($label) {
if ($label === Archiver::EVENT_NAME_NOT_SET) {
return false;
@@ -165,23 +168,24 @@ class API extends \Piwik\Plugin\API
}));
}
- $this->filterDataTable($dataTable);
+ $dataTable->filter('Piwik\Plugins\Events\DataTable\Filter\ReplaceEventNameNotSet');
+
return $dataTable;
}
- public function getCategory($idSite, $period, $date, $segment = false, $expanded = false, $secondaryDimension = false)
+ public function getCategory($idSite, $period, $date, $segment = false, $expanded = false, $secondaryDimension = false, $flat = false)
{
- return $this->getDataTable(__FUNCTION__, $idSite, $period, $date, $segment, $expanded, $idSubtable = false, $secondaryDimension);
+ return $this->getDataTable(__FUNCTION__, $idSite, $period, $date, $segment, $expanded, $idSubtable = false, $secondaryDimension, $flat);
}
- public function getAction($idSite, $period, $date, $segment = false, $expanded = false, $secondaryDimension = false)
+ public function getAction($idSite, $period, $date, $segment = false, $expanded = false, $secondaryDimension = false, $flat = false)
{
- return $this->getDataTable(__FUNCTION__, $idSite, $period, $date, $segment, $expanded, $idSubtable = false, $secondaryDimension);
+ return $this->getDataTable(__FUNCTION__, $idSite, $period, $date, $segment, $expanded, $idSubtable = false, $secondaryDimension, $flat);
}
- public function getName($idSite, $period, $date, $segment = false, $expanded = false, $secondaryDimension = false)
+ public function getName($idSite, $period, $date, $segment = false, $expanded = false, $secondaryDimension = false, $flat = false)
{
- return $this->getDataTable(__FUNCTION__, $idSite, $period, $date, $segment, $expanded, $idSubtable = false, $secondaryDimension);
+ return $this->getDataTable(__FUNCTION__, $idSite, $period, $date, $segment, $expanded, $idSubtable = false, $secondaryDimension, $flat);
}
public function getActionFromCategoryId($idSite, $period, $date, $idSubtable, $segment = false)
@@ -213,20 +217,4 @@ class API extends \Piwik\Plugin\API
{
return $this->getDataTable(__FUNCTION__, $idSite, $period, $date, $segment, $expanded = false, $idSubtable);
}
-
- /**
- * @param DataTable $dataTable
- */
- protected function filterDataTable($dataTable)
- {
- $dataTable->filter('Sort', array(Metrics::INDEX_NB_VISITS));
- $dataTable->queueFilter('ReplaceColumnNames');
- $dataTable->queueFilter('ReplaceSummaryRowLabel');
- $dataTable->filter(function (DataTable $table) {
- $row = $table->getRowFromLabel(Archiver::EVENT_NAME_NOT_SET);
- if ($row) {
- $row->setColumn('label', Piwik::translate('General_NotDefined', Piwik::translate('Events_EventName')));
- }
- });
- }
} \ No newline at end of file
diff --git a/plugins/Events/DataTable/Filter/ReplaceEventNameNotSet.php b/plugins/Events/DataTable/Filter/ReplaceEventNameNotSet.php
new file mode 100644
index 0000000000..a07695b5f8
--- /dev/null
+++ b/plugins/Events/DataTable/Filter/ReplaceEventNameNotSet.php
@@ -0,0 +1,39 @@
+<?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\Events\DataTable\Filter;
+
+use Piwik\DataTable\BaseFilter;
+use Piwik\DataTable\Row;
+use Piwik\DataTable;
+use Piwik\Piwik;
+use Piwik\Plugins\Events\Archiver;
+
+class ReplaceEventNameNotSet extends BaseFilter
+{
+ /**
+ * Constructor.
+ *
+ * @param DataTable $table The table to eventually filter.
+ */
+ public function __construct($table)
+ {
+ parent::__construct($table);
+ }
+
+ /**
+ * @param DataTable $table
+ */
+ public function filter($table)
+ {
+ $row = $table->getRowFromLabel(Archiver::EVENT_NAME_NOT_SET);
+ if ($row) {
+ $row->setColumn('label', Piwik::translate('General_NotDefined', Piwik::translate('Events_EventName')));
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/ExampleUI/Controller.php b/plugins/ExampleUI/Controller.php
index 9bfd517aa0..210093c8b5 100644
--- a/plugins/ExampleUI/Controller.php
+++ b/plugins/ExampleUI/Controller.php
@@ -90,6 +90,7 @@ class Controller extends \Piwik\Plugin\Controller
$view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns,
$selectableColumns = array('server1', 'server2'), 'My documentation', 'ExampleUI.getTemperaturesEvolution');
$view->requestConfig->filter_sort_column = 'label';
+ $view->requestConfig->filter_sort_order = 'asc';
if (empty($view->config->columns_to_display) && !empty($defaultColumns)) {
$view->config->columns_to_display = $defaultColumns;
diff --git a/plugins/Goals/Columns/Metrics/GoalSpecificProcessedMetric.php b/plugins/Goals/Columns/Metrics/GoalSpecificProcessedMetric.php
index 1ae1c41149..d32290bfdc 100644
--- a/plugins/Goals/Columns/Metrics/GoalSpecificProcessedMetric.php
+++ b/plugins/Goals/Columns/Metrics/GoalSpecificProcessedMetric.php
@@ -9,9 +9,11 @@ namespace Piwik\Plugins\Goals\Columns\Metrics;
use Piwik\Common;
use Piwik\DataTable\Row;
+use Piwik\Metrics;
use Piwik\Piwik;
use Piwik\Plugin\ProcessedMetric;
use Piwik\Plugins\Goals\API as GoalsAPI;
+use Piwik\Tracker\GoalManager;
/**
* Base class for processed metrics that are calculated using metrics that are
@@ -60,6 +62,16 @@ abstract class GoalSpecificProcessedMetric extends ProcessedMetric
$alternateKey = 'idgoal=' . $this->idGoal;
if (isset($allGoalMetrics[$alternateKey])) {
return $allGoalMetrics[$alternateKey];
+ } elseif ($this->idGoal === Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) {
+ $alternateKey = GoalManager::IDGOAL_ORDER;
+ if (isset($allGoalMetrics[$alternateKey])) {
+ return $allGoalMetrics[$alternateKey];
+ }
+ } elseif ($this->idGoal === Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART) {
+ $alternateKey = GoalManager::IDGOAL_CART;
+ if (isset($allGoalMetrics[$alternateKey])) {
+ return $allGoalMetrics[$alternateKey];
+ }
} else {
return array();
}
diff --git a/plugins/Installation/SystemCheck.php b/plugins/Installation/SystemCheck.php
index de55506884..93ed1ac75f 100644
--- a/plugins/Installation/SystemCheck.php
+++ b/plugins/Installation/SystemCheck.php
@@ -19,6 +19,7 @@ use Piwik\Filechecks;
use Piwik\Filesystem;
use Piwik\Http;
use Piwik\Piwik;
+use Piwik\Plugins\CoreUpdater;
use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\SettingsServer;
use Piwik\Url;
@@ -102,6 +103,9 @@ class SystemCheck
$infos['tracker_status'] = Common::getRequestVar('trackerStatus', 0, 'int');
$infos['is_nfs'] = Filesystem::checkIfFileSystemIsNFS();
+
+ $infos['https_update'] = CoreUpdater\Controller::isUpdatingOverHttps();
+
$infos = self::enrichSystemChecks($infos);
return $infos;
diff --git a/plugins/Installation/lang/en.json b/plugins/Installation/lang/en.json
index 9711d997c3..2d3afbf8c9 100644
--- a/plugins/Installation/lang/en.json
+++ b/plugins/Installation/lang/en.json
@@ -115,6 +115,8 @@
"SystemCheckCronArchiveProcess": "Archive Cron",
"SystemCheckCronArchiveProcessCLI": "Managing processes via CLI",
"SystemCheckPhpSetting": "To prevent some critical issue, you must set the following in your php.ini file: %s",
+ "SystemCheckUpdateHttps": "Update over HTTPS",
+ "SystemCheckUpdateHttpsNotSupported": "Piwik cannot use HTTPS to update, it will fall back to the insecure HTTP update. Check that CURL or allow_url_fopen is supported and that the openssl PHP extension is installed: http://piwik.org/faq/troubleshooting/faq_177/.",
"NotSupported": "not supported",
"Tables": "Creating the Tables",
"TablesCreatedSuccess": "Tables created with success!",
diff --git a/plugins/Installation/templates/_systemCheckSection.twig b/plugins/Installation/templates/_systemCheckSection.twig
index f797d18969..b56db9b672 100755
--- a/plugins/Installation/templates/_systemCheckSection.twig
+++ b/plugins/Installation/templates/_systemCheckSection.twig
@@ -356,6 +356,17 @@
</tr>
{% endif %}
+ <tr>
+ <td class="label">{{ 'Installation_SystemCheckUpdateHttps'|translate }}</td>
+ <td>
+ {% if infos.https_update %}
+ {{ ok }}
+ {% else %}
+ {{ warning }} {{ 'Installation_SystemCheckUpdateHttpsNotSupported'|translate }}
+ {% endif %}
+ </td>
+ </tr>
+
</table>
{% include "@Installation/_integrityDetails.twig" %}
diff --git a/plugins/Live/API.php b/plugins/Live/API.php
index ed11c6c277..68d7819aa6 100644
--- a/plugins/Live/API.php
+++ b/plugins/Live/API.php
@@ -60,17 +60,60 @@ class API extends \Piwik\Plugin\API
* @param int $idSite Id Site
* @param int $lastMinutes Number of minutes to look back at
* @param bool|string $segment
+ * @param array $showColumns The columns to show / not to request. Eg 'visits', 'actions', ...
+ * @param array $hideColumns The columns to hide / not to request. Eg 'visits', 'actions', ...
* @return array( visits => N, actions => M, visitsConverted => P )
*/
- public function getCounters($idSite, $lastMinutes, $segment = false)
+ public function getCounters($idSite, $lastMinutes, $segment = false, $showColumns = array(), $hideColumns = array())
{
Piwik::checkUserHasViewAccess($idSite);
$model = new Model();
- return $model->queryCounters($idSite, $lastMinutes, $segment);
+
+ $counters = array();
+
+ $hasVisits = true;
+ if ($this->shouldColumnBePresentInResponse('visits', $showColumns, $hideColumns)) {
+ $counters['visits'] = $model->getNumVisits($idSite, $lastMinutes, $segment);
+ $hasVisits = !empty($counters['visits']);
+ }
+
+ if ($this->shouldColumnBePresentInResponse('actions', $showColumns, $hideColumns)) {
+ if ($hasVisits) {
+ $counters['actions'] = $model->getNumActions($idSite, $lastMinutes, $segment);
+ } else {
+ $counters['actions'] = 0;
+ }
+ }
+
+ if ($this->shouldColumnBePresentInResponse('visitors', $showColumns, $hideColumns)) {
+ if ($hasVisits) {
+ $counters['visitors'] = $model->getNumVisitors($idSite, $lastMinutes, $segment);
+ } else {
+ $counters['visitors'] = 0;
+ }
+ }
+
+ if ($this->shouldColumnBePresentInResponse('visitsConverted', $showColumns, $hideColumns)) {
+ if ($hasVisits) {
+ $counters['visitsConverted'] = $model->getNumVisitsConverted($idSite, $lastMinutes, $segment);
+ } else {
+ $counters['visitsConverted'] = 0;
+ }
+ }
+
+ return array($counters);
+ }
+
+ private function shouldColumnBePresentInResponse($column, $showColumns, $hideColumns)
+ {
+ $show = (empty($showColumns) || in_array($column, $showColumns));
+ $hide = in_array($column, $hideColumns);
+
+ return $show && !$hide;
}
/**
- * The same functionnality can be obtained using segment=visitorId==$visitorId with getLastVisitsDetails
+ * The same functionality can be obtained using segment=visitorId==$visitorId with getLastVisitsDetails
*
* @deprecated
* @ignore
diff --git a/plugins/Live/Controller.php b/plugins/Live/Controller.php
index 421a0afb62..a2d3e44026 100644
--- a/plugins/Live/Controller.php
+++ b/plugins/Live/Controller.php
@@ -88,9 +88,9 @@ class Controller extends \Piwik\Plugin\Controller
private function setCounters($view)
{
$segment = Request::getRawSegmentFromRequest();
- $last30min = API::getInstance()->getCounters($this->idSite, $lastMinutes = 30, $segment);
+ $last30min = API::getInstance()->getCounters($this->idSite, $lastMinutes = 30, $segment, array('visits', 'actions'));
$last30min = $last30min[0];
- $today = API::getInstance()->getCounters($this->idSite, $lastMinutes = 24 * 60, $segment);
+ $today = API::getInstance()->getCounters($this->idSite, $lastMinutes = 24 * 60, $segment, array('visits', 'actions'));
$today = $today[0];
$view->visitorsCountHalfHour = $last30min['visits'];
$view->visitorsCountToday = $today['visits'];
diff --git a/plugins/Live/Model.php b/plugins/Live/Model.php
index 19a44ba1d6..0d1b0318fe 100644
--- a/plugins/Live/Model.php
+++ b/plugins/Live/Model.php
@@ -201,58 +201,101 @@ class Model
* @param $idSite
* @param $lastMinutes
* @param $segment
- * @return array
+ * @return int
* @throws Exception
*/
- public function queryCounters($idSite, $lastMinutes, $segment)
+ public function getNumActions($idSite, $lastMinutes, $segment)
{
- $lastMinutes = (int)$lastMinutes;
+ return $this->getLastMinutesCounterForQuery(
+ $idSite,
+ $lastMinutes,
+ $segment,
+ 'COUNT(*)',
+ 'log_link_visit_action',
+ 'log_link_visit_action.server_time >= ?'
+ );
+ }
- $counters = array(
- 'visits' => 0,
- 'actions' => 0,
- 'visitors' => 0,
- 'visitsConverted' => 0,
+ /**
+ * @param $idSite
+ * @param $lastMinutes
+ * @param $segment
+ * @return int
+ * @throws Exception
+ */
+ public function getNumVisitsConverted($idSite, $lastMinutes, $segment)
+ {
+ return $this->getLastMinutesCounterForQuery(
+ $idSite,
+ $lastMinutes,
+ $segment,
+ 'COUNT(*)',
+ 'log_conversion',
+ 'log_conversion.server_time >= ?'
);
+ }
+
+ /**
+ * @param $idSite
+ * @param $lastMinutes
+ * @param $segment
+ * @return int
+ * @throws Exception
+ */
+ public function getNumVisits($idSite, $lastMinutes, $segment)
+ {
+ return $this->getLastMinutesCounterForQuery(
+ $idSite,
+ $lastMinutes,
+ $segment,
+ 'COUNT(log_visit.visit_last_action_time)',
+ 'log_visit',
+ 'log_visit.visit_last_action_time >= ?'
+ );
+ }
+
+ /**
+ * @param $idSite
+ * @param $lastMinutes
+ * @param $segment
+ * @return int
+ * @throws Exception
+ */
+ public function getNumVisitors($idSite, $lastMinutes, $segment)
+ {
+ return $this->getLastMinutesCounterForQuery(
+ $idSite,
+ $lastMinutes,
+ $segment,
+ 'COUNT(DISTINCT log_visit.idvisitor)',
+ 'log_visit',
+ 'log_visit.visit_last_action_time >= ?'
+ );
+ }
+
+ private function getLastMinutesCounterForQuery($idSite, $lastMinutes, $segment, $select, $from, $where)
+ {
+ $lastMinutes = (int)$lastMinutes;
if (empty($lastMinutes)) {
- return array($counters);
+ return 0;
}
- list($whereIdSites, $idSites) = $this->getIdSitesWhereClause($idSite);
+ list($whereIdSites, $idSites) = $this->getIdSitesWhereClause($idSite, $from);
- $select = "count(*) as visits, COUNT(DISTINCT log_visit.idvisitor) as visitors";
- $where = $whereIdSites . "AND log_visit.visit_last_action_time >= ?";
- $bind = $idSites;
+ $bind = $idSites;
$bind[] = Date::factory(time() - $lastMinutes * 60)->toString('Y-m-d H:i:s');
- $segment = new Segment($segment, $idSite);
- $query = $segment->getSelectQuery($select, 'log_visit', $where, $bind);
-
- $data = Db::fetchAll($query['sql'], $query['bind']);
-
- $counters['visits'] = $data[0]['visits'];
- $counters['visitors'] = $data[0]['visitors'];
+ $where = $whereIdSites . "AND " . $where;
- $select = "count(*)";
- $from = 'log_link_visit_action';
- list($whereIdSites) = $this->getIdSitesWhereClause($idSite, $from);
- $where = $whereIdSites . "AND log_link_visit_action.server_time >= ?";
- $query = $segment->getSelectQuery($select, $from, $where, $bind);
- $counters['actions'] = Db::fetchOne($query['sql'], $query['bind']);
+ $segment = new Segment($segment, $idSite);
+ $query = $segment->getSelectQuery($select, $from, $where, $bind);
- $select = "count(*)";
- $from = 'log_conversion';
- list($whereIdSites) = $this->getIdSitesWhereClause($idSite, $from);
- $where = $whereIdSites . "AND log_conversion.server_time >= ?";
- $query = $segment->getSelectQuery($select, $from, $where, $bind);
- $counters['visitsConverted'] = Db::fetchOne($query['sql'], $query['bind']);
+ $numVisitors = Db::fetchOne($query['sql'], $query['bind']);
- return array($counters);
+ return $numVisitors;
}
-
-
/**
* @param $idSite
* @param string $table
diff --git a/plugins/Live/Reports/GetSimpleLastVisitCount.php b/plugins/Live/Reports/GetSimpleLastVisitCount.php
index 34ba773fa9..e2a17135c5 100644
--- a/plugins/Live/Reports/GetSimpleLastVisitCount.php
+++ b/plugins/Live/Reports/GetSimpleLastVisitCount.php
@@ -30,7 +30,8 @@ class GetSimpleLastVisitCount extends Base
{
$lastMinutes = Config::getInstance()->General[Controller::SIMPLE_VISIT_COUNT_WIDGET_LAST_MINUTES_CONFIG_KEY];
- $lastNData = Request::processRequest('Live.getCounters', array('lastMinutes' => $lastMinutes));
+ $params = array('lastMinutes' => $lastMinutes, 'showColumns' => array('visits', 'visitors', 'actions'));
+ $lastNData = Request::processRequest('Live.getCounters', $params);
$formatter = new Formatter();
diff --git a/plugins/Live/tests/System/APITest.php b/plugins/Live/tests/System/APITest.php
index 2c85088a19..4b65a5ae4e 100644
--- a/plugins/Live/tests/System/APITest.php
+++ b/plugins/Live/tests/System/APITest.php
@@ -70,6 +70,38 @@ class APITest extends SystemTestCase
$this->assertEquals($this->buildCounter(0, 0, 0, 0), $counters);
}
+ public function test_GetCounters_ShouldHideAllColumnsIfRequested()
+ {
+ $exampleCounter = $this->buildCounter(0, 0, 0, 0);
+ $counters = $this->api->getCounters($this->idSite, 5, false, array(), array_keys($exampleCounter[0]));
+ $this->assertEquals(array(array()), $counters);
+ }
+
+ public function test_GetCounters_ShouldHideSomeColumnsIfRequested()
+ {
+ $counters = $this->api->getCounters($this->idSite, 20, false, array(), array('visitsConverted', 'visitors'));
+ $this->assertEquals(array(array('visits' => 24, 'actions' => 60)), $counters);
+ }
+
+ public function test_GetCounters_ShouldShowAllColumnsIfRequested()
+ {
+ $counter = $this->buildCounter(24, 60, 20, 40);
+ $counters = $this->api->getCounters($this->idSite, 20, false, array_keys($counter[0]));
+ $this->assertEquals($counter, $counters);
+ }
+
+ public function test_GetCounters_ShouldShowSomeColumnsIfRequested()
+ {
+ $counters = $this->api->getCounters($this->idSite, 20, false, array('visits', 'actions'));
+ $this->assertEquals(array(array('visits' => 24, 'actions' => 60)), $counters);
+ }
+
+ public function test_GetCounters_ShouldHideColumnIfGivenInShowAndHide()
+ {
+ $counters = $this->api->getCounters($this->idSite, 20, false, array('visits', 'actions'), array('actions'));
+ $this->assertEquals(array(array('visits' => 24)), $counters);
+ }
+
private function trackSomeVisits()
{
$nowTimestamp = time();
diff --git a/plugins/Login/lang/en.json b/plugins/Login/lang/en.json
index d43d85c212..3164a4bbcd 100644
--- a/plugins/Login/lang/en.json
+++ b/plugins/Login/lang/en.json
@@ -16,7 +16,7 @@
"PasswordChanged": "Your password has been changed.",
"PasswordRepeat": "Password (repeat)",
"PasswordsDoNotMatch": "Passwords do not match.",
- "PluginDescription": "Provides authentication via username and password as well as password reset functionnality. Authentication method can be changed by using another Login plugin such as LoginLdap available on the Marketplace.",
+ "PluginDescription": "Provides authentication via username and password as well as password reset functionality. Authentication method can be changed by using another Login plugin such as LoginLdap available on the Marketplace.",
"RememberMe": "Remember Me",
"ResetPasswordInstructions": "Enter a new password for your account."
}
diff --git a/plugins/Provider/Columns/Provider.php b/plugins/Provider/Columns/Provider.php
index 24ab6cecd2..b7ca57e9c9 100644
--- a/plugins/Provider/Columns/Provider.php
+++ b/plugins/Provider/Columns/Provider.php
@@ -9,7 +9,7 @@
namespace Piwik\Plugins\Provider\Columns;
use Piwik\Common;
-use Piwik\IP;
+use Piwik\Network\IP;
use Piwik\Network\IPUtils;
use Piwik\Piwik;
use Piwik\Plugin\Dimension\VisitDimension;
@@ -87,12 +87,17 @@ class Provider extends VisitDimension
/**
* Returns the hostname given the IP address string
*
- * @param string $ip IP Address
+ * @param string $ipStr IP Address
* @return string hostname (or human-readable IP address)
*/
- private function getHost($ip)
+ private function getHost($ipStr)
{
- return trim(strtolower(@IP::getHostByAddr($ip)));
+ $ip = IP::fromStringIP($ipStr);
+
+ $host = $ip->getHostname();
+ $host = ($host === null ? $ipStr : $host);
+
+ return trim(strtolower($host));
}
public function getName()
diff --git a/plugins/QueuedTracking b/plugins/QueuedTracking
-Subproject ff1228265cc695fbec8b2997f442ed0bb90f289
+Subproject bc39d75e4c9df58c865ae44f6eae23676e7baf9
diff --git a/plugins/Referrers/API.php b/plugins/Referrers/API.php
index 4ac28978e3..2cacbb2833 100644
--- a/plugins/Referrers/API.php
+++ b/plugins/Referrers/API.php
@@ -13,6 +13,7 @@ use Piwik\API\ResponseBuilder;
use Piwik\Archive;
use Piwik\Common;
use Piwik\DataTable\Row;
+use Piwik\DataTable\Manager as DataTableManager;
use Piwik\DataTable;
use Piwik\Date;
use Piwik\Metrics;
@@ -43,7 +44,6 @@ class API extends \Piwik\Plugin\API
protected function getDataTable($name, $idSite, $period, $date, $segment, $expanded = false, $idSubtable = null)
{
$dataTable = Archive::getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded, $idSubtable);
- $dataTable->filter('Sort', array(Metrics::INDEX_NB_VISITS, 'desc', $naturalSort = false, $expanded));
$dataTable->queueFilter('ReplaceColumnNames');
return $dataTable;
}
@@ -137,19 +137,19 @@ class API extends \Piwik\Plugin\API
return $dataTable;
}
- public function getKeywords($idSite, $period, $date, $segment = false, $expanded = false)
+ public function getKeywords($idSite, $period, $date, $segment = false, $expanded = false, $flat = false)
{
- $dataTable = $this->getDataTable(Archiver::KEYWORDS_RECORD_NAME, $idSite, $period, $date, $segment, $expanded);
- $dataTable->filter('AddSegmentValue');
- $dataTable->queueFilter('PrependSegment', array('referrerType==search;'));
+ $dataTable = Archive::createDataTableFromArchive(Archiver::KEYWORDS_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $flat);
- $dataTable = $this->handleKeywordNotDefined($dataTable);
- return $dataTable;
- }
+ if ($flat) {
+ $dataTable->filterSubtables('Piwik\Plugins\Referrers\DataTable\Filter\SearchEnginesFromKeywordId', array($dataTable));
+ } else {
+ $dataTable->filter('AddSegmentValue');
+ $dataTable->queueFilter('PrependSegment', array('referrerType==search;'));
+ }
+
+ $dataTable->queueFilter('Piwik\Plugins\Referrers\DataTable\Filter\KeywordNotDefined');
- protected function handleKeywordNotDefined($dataTable)
- {
- $dataTable->queueFilter('ColumnCallbackReplace', array('label', __NAMESPACE__ . '\API::getCleanKeyword'));
return $dataTable;
}
@@ -225,27 +225,28 @@ class API extends \Piwik\Plugin\API
public function getSearchEnginesFromKeywordId($idSite, $period, $date, $idSubtable, $segment = false)
{
$dataTable = $this->getDataTable(Archiver::KEYWORDS_RECORD_NAME, $idSite, $period, $date, $segment, $expanded = false, $idSubtable);
- $dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', __NAMESPACE__ . '\getSearchEngineUrlFromName'));
- $dataTable->queueFilter('MetadataCallbackAddMetadata', array('url', 'logo', __NAMESPACE__ . '\getSearchEngineLogoFromUrl'));
- // get the keyword and create the URL to the search result page
$keywords = $this->getKeywords($idSite, $period, $date, $segment);
- $subTable = $keywords->getRowFromIdSubDataTable($idSubtable);
- if ($subTable) {
- $keyword = $subTable->getColumn('label');
- $dataTable->queueFilter('MetadataCallbackReplace', array('url', __NAMESPACE__ . '\getSearchEngineUrlFromUrlAndKeyword', array($keyword)));
- }
+ $dataTable->filter('Piwik\Plugins\Referrers\DataTable\Filter\SearchEnginesFromKeywordId', array($keywords, $idSubtable));
+
return $dataTable;
}
- public function getSearchEngines($idSite, $period, $date, $segment = false, $expanded = false)
+ public function getSearchEngines($idSite, $period, $date, $segment = false, $expanded = false, $flat = false)
{
- $dataTable = $this->getDataTable(Archiver::SEARCH_ENGINES_RECORD_NAME, $idSite, $period, $date, $segment, $expanded);
+ $dataTable = Archive::createDataTableFromArchive(Archiver::SEARCH_ENGINES_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $flat);
+
+ if ($flat) {
+ $dataTable->filter('ColumnCallbackAddMetadata', array('label', 'url', __NAMESPACE__ . '\getSearchEngineUrlFromName'));
+ $dataTable->filter('MetadataCallbackAddMetadata', array('url', 'logo', __NAMESPACE__ . '\getSearchEngineLogoFromUrl'));
+ $dataTable->filterSubtables('Piwik\Plugins\Referrers\DataTable\Filter\KeywordsFromSearchEngineId', array($dataTable));
+ } else {
+ $dataTable->filter('AddSegmentByLabel', array('referrerName'));
+ $dataTable->queueFilter('PrependSegment', array('referrerType==search;'));
+ $dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', __NAMESPACE__ . '\getSearchEngineUrlFromName'));
+ $dataTable->queueFilter('MetadataCallbackAddMetadata', array('url', 'logo', __NAMESPACE__ . '\getSearchEngineLogoFromUrl'));
+ }
- $dataTable->filter('AddSegmentByLabel', array('referrerName'));
- $dataTable->queueFilter('PrependSegment', array('referrerType==search;'));
- $dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', __NAMESPACE__ . '\getSearchEngineUrlFromName'));
- $dataTable->queueFilter('MetadataCallbackAddMetadata', array('url', 'logo', __NAMESPACE__ . '\getSearchEngineLogoFromUrl'));
return $dataTable;
}
@@ -257,26 +258,8 @@ class API extends \Piwik\Plugin\API
$searchEngines = $this->getSearchEngines($idSite, $period, $date, $segment);
$searchEngines->applyQueuedFilters();
- if ($searchEngines instanceof DataTable\Map) {
- $dataTables = $searchEngines->getDataTables();
-
- // find first datatable containing data
- foreach ($dataTables as $subTable) {
+ $dataTable->filter('Piwik\Plugins\Referrers\DataTable\Filter\KeywordsFromSearchEngineId', array($searchEngines, $idSubtable));
- $subTableRow = $subTable->getRowFromIdSubDataTable($idSubtable);
- if (!empty($subTableRow)) {
- break;
- }
- }
- } else {
- $subTableRow = $searchEngines->getRowFromIdSubDataTable($idSubtable);
- }
-
- if (!empty($subTableRow)) {
- $searchEngineUrl = $subTableRow->getMetadata('url');
- $dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', __NAMESPACE__ . '\getSearchEngineUrlFromKeywordAndUrl', array($searchEngineUrl)));
- }
- $dataTable = $this->handleKeywordNotDefined($dataTable);
return $dataTable;
}
@@ -296,22 +279,24 @@ class API extends \Piwik\Plugin\API
return $dataTable;
}
- public function getWebsites($idSite, $period, $date, $segment = false, $expanded = false)
+ public function getWebsites($idSite, $period, $date, $segment = false, $expanded = false, $flat = false)
{
- $dataTable = $this->getDataTable(Archiver::WEBSITES_RECORD_NAME, $idSite, $period, $date, $segment, $expanded);
- $dataTable->filter('AddSegmentByLabel', array('referrerName'));
+ $dataTable = Archive::createDataTableFromArchive(Archiver::WEBSITES_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $flat, $idSubtable = null);
+
+ if ($flat) {
+ $dataTable->filterSubtables('Piwik\Plugins\Referrers\DataTable\Filter\UrlsFromWebsiteId');
+ } else {
+ $dataTable->filter('AddSegmentByLabel', array('referrerName'));
+ }
+
return $dataTable;
}
public function getUrlsFromWebsiteId($idSite, $period, $date, $idSubtable, $segment = false)
{
$dataTable = $this->getDataTable(Archiver::WEBSITES_RECORD_NAME, $idSite, $period, $date, $segment, $expanded = false, $idSubtable);
- // the htmlspecialchars_decode call is for BC for before 1.1
- // as the Referrer URL was previously encoded in the log tables, but is now recorded raw
- $dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', function ($label) {
- return htmlspecialchars_decode($label);
- }));
- $dataTable->queueFilter('ColumnCallbackReplace', array('label', __NAMESPACE__ . '\getPathFromUrl'));
+ $dataTable->filter('Piwik\Plugins\Referrers\DataTable\Filter\UrlsFromWebsiteId');
+
return $dataTable;
}
@@ -324,11 +309,13 @@ class API extends \Piwik\Plugin\API
* @param string $date
* @param string|bool $segment
* @param bool $expanded
+ * @param bool $flat
* @return DataTable
*/
- public function getSocials($idSite, $period, $date, $segment = false, $expanded = false)
+ public function getSocials($idSite, $period, $date, $segment = false, $expanded = false, $flat = false)
{
- $dataTable = $this->getDataTable(Archiver::WEBSITES_RECORD_NAME, $idSite, $period, $date, $segment, $expanded);
+ $dataTable = Archive::createDataTableFromArchive(Archiver::WEBSITES_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, false);
+
$dataTable->filter('ColumnCallbackDeleteRow', array('label', function ($url) { return !isSocialUrl($url); }));
$dataTable->filter('ColumnCallbackAddMetadata', array('label', 'url', __NAMESPACE__ . '\getSocialMainUrl'));
$dataTable->filter('GroupBy', array('label', __NAMESPACE__ . '\getSocialNetworkFromDomain'));
@@ -336,6 +323,10 @@ class API extends \Piwik\Plugin\API
$this->setSocialIdSubtables($dataTable);
$this->removeSubtableMetadata($dataTable);
+ if ($flat) {
+ $this->buildExpandedTableForFlattenGetSocials($idSite, $period, $date, $segment, $expanded, $dataTable);
+ }
+
$dataTable->queueFilter('MetadataCallbackAddMetadata', array('url', 'logo', __NAMESPACE__ . '\getSocialsLogoFromUrl'));
return $dataTable;
@@ -385,13 +376,7 @@ class API extends \Piwik\Plugin\API
// merge the datatable's subtables which contain the individual URLs
$dataTable = $dataTable->mergeSubtables();
- // make url labels clickable
- $dataTable->filter('ColumnCallbackAddMetadata', array('label', 'url'));
-
- // prettify the DataTable
- $dataTable->filter('ColumnCallbackReplace', array('label', __NAMESPACE__ . '\removeUrlProtocol'));
- $dataTable->filter('Sort', array(Metrics::INDEX_NB_VISITS, 'desc', $naturalSort = false, $expanded));
- $dataTable->queueFilter('ReplaceColumnNames');
+ $dataTable->filter('Piwik\Plugins\Referrers\DataTable\Filter\UrlsForSocial', array($expanded));
return $dataTable;
}
@@ -540,4 +525,45 @@ class API extends \Piwik\Plugin\API
}
}
+ /**
+ * @param int $idSite
+ * @param string $period
+ * @param string $date
+ * @param string|false $segment
+ * @param bool $expanded
+ * @param DataTable $dataTable
+ */
+ private function buildExpandedTableForFlattenGetSocials($idSite, $period, $date, $segment, $expanded, $dataTable)
+ {
+ $urlsTable = Archive::createDataTableFromArchive(Archiver::WEBSITES_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $flat = true);
+ $urlsTable->filter('ColumnCallbackDeleteRow', array('label', function ($url) {
+ return !isSocialUrl($url);
+ }));
+ $urlsTable = $urlsTable->mergeSubtables();
+
+ foreach ($dataTable->getRows() as $row) {
+ $row->removeSubtable();
+
+ $social = $row->getColumn('label');
+ $newTable = $urlsTable->getEmptyClone();
+
+ $rows = $urlsTable->getRows();
+ foreach ($rows as $id => $urlsTableRow) {
+ $url = $urlsTableRow->getColumn('label');
+ if (isSocialUrl($url, $social)) {
+ $newTable->addRow($urlsTableRow);
+ $urlsTable->deleteRow($id);
+ }
+ }
+
+ if ($newTable->getRowsCount()) {
+ $newTable->filter('Piwik\Plugins\Referrers\DataTable\Filter\UrlsForSocial', array($expanded));
+ $row->setSubtable($newTable);
+ }
+ }
+
+ Common::destroy($urlsTable);
+ $urlsTable = null;
+ }
+
}
diff --git a/plugins/Referrers/DataTable/Filter/KeywordNotDefined.php b/plugins/Referrers/DataTable/Filter/KeywordNotDefined.php
new file mode 100644
index 0000000000..dbee6f865b
--- /dev/null
+++ b/plugins/Referrers/DataTable/Filter/KeywordNotDefined.php
@@ -0,0 +1,25 @@
+<?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\Referrers\DataTable\Filter;
+
+use Piwik\DataTable\Row;
+use Piwik\DataTable;
+
+class KeywordNotDefined extends DataTable\Filter\ColumnCallbackReplace
+{
+ /**
+ * Constructor.
+ *
+ * @param DataTable $table The table to eventually filter.
+ */
+ public function __construct($table)
+ {
+ parent::__construct($table, 'label', 'Piwik\Plugins\Referrers\API::getCleanKeyword');
+ }
+} \ No newline at end of file
diff --git a/plugins/Referrers/DataTable/Filter/KeywordsFromSearchEngineId.php b/plugins/Referrers/DataTable/Filter/KeywordsFromSearchEngineId.php
new file mode 100644
index 0000000000..1688713a86
--- /dev/null
+++ b/plugins/Referrers/DataTable/Filter/KeywordsFromSearchEngineId.php
@@ -0,0 +1,61 @@
+<?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\Referrers\DataTable\Filter;
+
+use Piwik\DataTable\BaseFilter;
+use Piwik\DataTable\Row;
+use Piwik\DataTable;
+
+class KeywordsFromSearchEngineId extends BaseFilter
+{
+ /**
+ * @var DataTable
+ */
+ private $firstLevelSearchEnginesTable;
+
+ /**
+ * @var int
+ */
+ private $idSubtable;
+
+ /**
+ * Constructor.
+ *
+ * @param DataTable $table The table to eventually filter.
+ */
+ public function __construct($table, $firstLevelSearchEnginesTable, $idSubtable = null)
+ {
+ parent::__construct($table);
+
+ $this->firstLevelSearchEnginesTable = $firstLevelSearchEnginesTable;
+ $this->idSubtable = $idSubtable;
+ }
+
+ /**
+ * @param DataTable $table
+ */
+ public function filter($table)
+ {
+ $idSubtable = $this->idSubtable ? : $table->getId();
+ $subTableRow = $this->firstLevelSearchEnginesTable->getRowFromIdSubDataTable($idSubtable);
+
+ if (!empty($subTableRow)) {
+ $searchEngineUrl = $subTableRow->getMetadata('url');
+ $table->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', 'Piwik\Plugins\Referrers\getSearchEngineUrlFromKeywordAndUrl', array($searchEngineUrl)));
+ $table->queueFilter(function (DataTable $table) {
+ $row = $table->getRowFromId(DataTable::ID_SUMMARY_ROW);
+ if ($row) {
+ $row->deleteMetadata('url');
+ }
+ });
+ }
+
+ $table->queueFilter('Piwik\Plugins\Referrers\DataTable\Filter\KeywordNotDefined');
+ }
+} \ No newline at end of file
diff --git a/plugins/Referrers/DataTable/Filter/SearchEnginesFromKeywordId.php b/plugins/Referrers/DataTable/Filter/SearchEnginesFromKeywordId.php
new file mode 100644
index 0000000000..feab8636af
--- /dev/null
+++ b/plugins/Referrers/DataTable/Filter/SearchEnginesFromKeywordId.php
@@ -0,0 +1,63 @@
+<?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\Referrers\DataTable\Filter;
+
+use Piwik\DataTable\BaseFilter;
+use Piwik\DataTable\Row;
+use Piwik\DataTable;
+
+class SearchEnginesFromKeywordId extends BaseFilter
+{
+ /**
+ * @var DataTable
+ */
+ private $firstLevelKeywordTable;
+
+ /**
+ * @var int
+ */
+ private $idSubtable;
+
+ /**
+ * Constructor.
+ *
+ * @param DataTable $table The table to eventually filter.
+ */
+ public function __construct($table, $firstLevelKeywordTable, $idSubtable = null)
+ {
+ parent::__construct($table);
+
+ $this->firstLevelKeywordTable = $firstLevelKeywordTable;
+ $this->idSubtable = $idSubtable;
+ }
+
+ /**
+ * @param DataTable $table
+ */
+ public function filter($table)
+ {
+ $idSubtable = $this->idSubtable ? : $table->getId();
+
+ $table->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', 'Piwik\Plugins\Referrers\getSearchEngineUrlFromName'));
+ $table->queueFilter('MetadataCallbackAddMetadata', array('url', 'logo', 'Piwik\Plugins\Referrers\getSearchEngineLogoFromUrl'));
+
+ // get the keyword and create the URL to the search result page
+ $rootRow = $this->firstLevelKeywordTable->getRowFromIdSubDataTable($idSubtable);
+ if ($rootRow) {
+ $keyword = $rootRow->getColumn('label');
+ $table->queueFilter('MetadataCallbackReplace', array('url', 'Piwik\Plugins\Referrers\getSearchEngineUrlFromUrlAndKeyword', array($keyword)));
+ $table->queueFilter(function (DataTable $table) {
+ $row = $table->getRowFromId(DataTable::ID_SUMMARY_ROW);
+ if ($row) {
+ $row->deleteMetadata('url');
+ }
+ });
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/Referrers/DataTable/Filter/UrlsForSocial.php b/plugins/Referrers/DataTable/Filter/UrlsForSocial.php
new file mode 100644
index 0000000000..ad86093060
--- /dev/null
+++ b/plugins/Referrers/DataTable/Filter/UrlsForSocial.php
@@ -0,0 +1,49 @@
+<?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\Referrers\DataTable\Filter;
+
+use Piwik\DataTable\BaseFilter;
+use Piwik\DataTable\Row;
+use Piwik\DataTable;
+use Piwik\Metrics;
+
+class UrlsForSocial extends BaseFilter
+{
+ /**
+ * @var bool
+ */
+ private $sortRecursive;
+
+ /**
+ * Constructor.
+ *
+ * @param DataTable $table The table to eventually filter.
+ * @param bool $sortRecursive Whether to sort recursive or not
+ */
+ public function __construct($table, $sortRecursive)
+ {
+ parent::__construct($table);
+
+ $this->sortRecursive = $sortRecursive;
+ }
+
+ /**
+ * @param DataTable $table
+ */
+ public function filter($table)
+ {
+ // make url labels clickable
+ $table->filter('ColumnCallbackAddMetadata', array('label', 'url'));
+
+ // prettify the DataTable
+ $table->filter('ColumnCallbackReplace', array('label', 'Piwik\Plugins\Referrers\removeUrlProtocol'));
+ $table->filter('Sort', array(Metrics::INDEX_NB_VISITS, 'desc', $naturalSort = false, $this->sortRecursive));
+ $table->queueFilter('ReplaceColumnNames');
+ }
+} \ No newline at end of file
diff --git a/plugins/Referrers/DataTable/Filter/UrlsFromWebsiteId.php b/plugins/Referrers/DataTable/Filter/UrlsFromWebsiteId.php
new file mode 100644
index 0000000000..c35d60b463
--- /dev/null
+++ b/plugins/Referrers/DataTable/Filter/UrlsFromWebsiteId.php
@@ -0,0 +1,46 @@
+<?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\Referrers\DataTable\Filter;
+
+use Piwik\DataTable\BaseFilter;
+use Piwik\DataTable\Row;
+use Piwik\DataTable;
+
+class UrlsFromWebsiteId extends BaseFilter
+{
+ /**
+ * Constructor.
+ *
+ * @param DataTable $table The table to eventually filter.
+ */
+ public function __construct($table)
+ {
+ parent::__construct($table);
+ }
+
+ /**
+ * @param DataTable $table
+ */
+ public function filter($table)
+ {
+ // the htmlspecialchars_decode call is for BC for before 1.1
+ // as the Referrer URL was previously encoded in the log tables, but is now recorded raw
+ $table->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', function ($label) {
+ return htmlspecialchars_decode($label);
+ }));
+ $table->queueFilter('ColumnCallbackReplace', array('label', 'Piwik\Plugins\Referrers\getPathFromUrl'));
+
+ foreach ($table->getRows() as $row) {
+ $subtable = $row->getSubtable();
+ if ($subtable) {
+ $this->filter($subtable);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/Referrers/Reports/GetWebsites.php b/plugins/Referrers/Reports/GetWebsites.php
index e394eb43d9..18f9336a63 100644
--- a/plugins/Referrers/Reports/GetWebsites.php
+++ b/plugins/Referrers/Reports/GetWebsites.php
@@ -21,6 +21,7 @@ class GetWebsites extends Base
$this->dimension = new Website();
$this->name = Piwik::translate('CorePluginsAdmin_Websites');
$this->documentation = Piwik::translate('Referrers_WebsitesReportDocumentation', '<br />');
+ $this->recursiveLabelSeparator = '/';
$this->actionToLoadSubTables = 'getUrlsFromWebsiteId';
$this->hasGoalMetrics = true;
$this->order = 5;
diff --git a/plugins/SecurityInfo b/plugins/SecurityInfo
-Subproject a7e2d59ac96e39e1141808fd944e863dc9588e8
+Subproject f037ffc0d6402d084ff1b6525b4c010f56e4276
diff --git a/plugins/SitesManager/Controller.php b/plugins/SitesManager/Controller.php
index e7299ab03e..bf810bf5bf 100644
--- a/plugins/SitesManager/Controller.php
+++ b/plugins/SitesManager/Controller.php
@@ -15,6 +15,7 @@ use Piwik\Piwik;
use Piwik\SettingsPiwik;
use Piwik\Site;
use Piwik\Tracker\TrackerCodeGenerator;
+use Piwik\Url;
use Piwik\View;
/**
@@ -118,4 +119,20 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
header('Content-Disposition: attachment; filename="' . $filename . '"');
return file_get_contents($path . $filename);
}
+
+ public function siteWithoutData()
+ {
+ $javascriptGenerator = new TrackerCodeGenerator();
+ $piwikUrl = Url::getCurrentUrlWithoutFileName();
+
+ return $this->renderTemplate('siteWithoutData', array(
+ 'siteName' => $this->site->getName(),
+ 'trackingHelp' => $this->renderTemplate('_displayJavascriptCode', array(
+ 'displaySiteName' => $this->site->getName(),
+ 'jsTag' => $javascriptGenerator->generate($this->idSite, $piwikUrl),
+ 'idSite' => $this->idSite,
+ 'piwikUrl' => $piwikUrl,
+ )),
+ ));
+ }
}
diff --git a/plugins/SitesManager/SitesManager.php b/plugins/SitesManager/SitesManager.php
index ca47a50540..6427dec875 100644
--- a/plugins/SitesManager/SitesManager.php
+++ b/plugins/SitesManager/SitesManager.php
@@ -9,6 +9,7 @@
namespace Piwik\Plugins\SitesManager;
use Piwik\Archive\ArchiveInvalidator;
use Piwik\Tracker\Cache;
+use Piwik\Tracker\Model as TrackerModel;
/**
*
@@ -29,10 +30,29 @@ class SitesManager extends \Piwik\Plugin
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'Tracker.Cache.getSiteAttributes' => 'recordWebsiteDataInCache',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
- 'SitesManager.deleteSite.end' => 'onSiteDeleted'
+ 'SitesManager.deleteSite.end' => 'onSiteDeleted',
+ 'Request.dispatch' => 'redirectDashboardToWelcomePage',
);
}
+ public function redirectDashboardToWelcomePage(&$module, &$action)
+ {
+ if ($module !== 'CoreHome' || $action !== 'index') {
+ return;
+ }
+
+ $siteId = Common::getRequestVar('idSite', false, 'int');
+ if (!$siteId) {
+ return;
+ }
+
+ $trackerModel = new TrackerModel();
+ if ($trackerModel->isSiteEmpty($siteId)) {
+ $module = 'SitesManager';
+ $action = 'siteWithoutData';
+ }
+ }
+
public function onSiteDeleted($idSite)
{
// we do not delete logs here on purpose (you can run these queries on the log_ tables to delete all data)
diff --git a/plugins/SitesManager/lang/en.json b/plugins/SitesManager/lang/en.json
index 072921ef48..7ee253b445 100644
--- a/plugins/SitesManager/lang/en.json
+++ b/plugins/SitesManager/lang/en.json
@@ -64,6 +64,9 @@
"ShowTrackingTag": "View Tracking code",
"Sites": "Websites",
"SiteSearchUse": "You can use Piwik to track and report what visitors are searching in your website's internal search engine.",
+ "SiteWithoutDataTitle": "No data has been recorded yet",
+ "SiteWithoutDataDescription": "No analytics data has been tracked for this website yet.",
+ "SiteWithoutDataSetupTracking": "Please set up the %1$sJavaScript tracking code%2$s on your website and refresh the page.",
"SuperUserAccessCan": "A user with Super User access can also %s specify global settings%s for new websites.",
"Timezone": "Time zone",
"TrackingSiteSearch": "Tracking Internal Site Search",
diff --git a/plugins/SitesManager/stylesheets/SitesManager.less b/plugins/SitesManager/stylesheets/SitesManager.less
index de6c74f990..d847d0e8a7 100644
--- a/plugins/SitesManager/stylesheets/SitesManager.less
+++ b/plugins/SitesManager/stylesheets/SitesManager.less
@@ -35,4 +35,21 @@ td.editable-site-field:hover {
.link_but:hover > span {
text-decoration: underline;
-} \ No newline at end of file
+}
+
+.site-without-data {
+ padding: 15px;
+ h2 {
+ border-bottom: 1px solid #ccc;
+ margin: 25px 0;
+ padding: 0 0 5px 0;
+ font-size: 24px;
+ }
+ h3 {
+ margin: 15px 0;
+ font-size: 18px;
+ line-height: 24px;
+ font-weight: normal;
+ color: black;
+ }
+}
diff --git a/plugins/SitesManager/templates/siteWithoutData.twig b/plugins/SitesManager/templates/siteWithoutData.twig
new file mode 100644
index 0000000000..20b6326644
--- /dev/null
+++ b/plugins/SitesManager/templates/siteWithoutData.twig
@@ -0,0 +1,25 @@
+{% extends "dashboard.twig" %}
+
+{% block notification %}{% endblock %}
+
+{% block content %}
+
+ {% include "@CoreHome/_siteSelectHeader.twig" %}
+
+ <div class="site-without-data">
+
+ <h2>{{ 'SitesManager_SiteWithoutDataTitle'|translate }}</h2>
+
+ <p>
+ {{ 'SitesManager_SiteWithoutDataDescription'|translate }}
+ {{ 'SitesManager_SiteWithoutDataSetupTracking'|translate('<a href="' ~ linkTo({
+ 'module': 'CoreAdminHome',
+ 'action': 'trackingCodeGenerator',
+ }) ~ '">', '</a>')|raw }}
+ </p>
+
+ {{ trackingHelp|raw }}
+
+ </div>
+
+{% endblock %}
diff --git a/plugins/TasksTimetable b/plugins/TasksTimetable
-Subproject 4af9daf3388f59159cf0ff9eb60b8bc38461149
+Subproject a0f38fec7cf905d34059ec1b6a207156adf7579
diff --git a/plugins/TestRunner/Aws/config.ini.php b/plugins/TestRunner/Aws/config.ini.php
index a6111e5685..65c4498b89 100644
--- a/plugins/TestRunner/Aws/config.ini.php
+++ b/plugins/TestRunner/Aws/config.ini.php
@@ -12,6 +12,7 @@ charset = "utf8"
request_uri = "/"
[database_tests]
+username = "root"
password = "secure"
tables_prefix = ""
diff --git a/plugins/TestRunner/Commands/TestsRunOnAws.php b/plugins/TestRunner/Commands/TestsRunOnAws.php
index 8ff81fa0a5..65bce267e0 100644
--- a/plugins/TestRunner/Commands/TestsRunOnAws.php
+++ b/plugins/TestRunner/Commands/TestsRunOnAws.php
@@ -35,9 +35,10 @@ class TestsRunOnAws extends ConsoleCommand
{
$this->setName('tests:run-aws');
$this->addArgument('testsuite', InputArgument::OPTIONAL, 'Allowed values: ' . implode(', ', $this->allowedTestSuites));
+ $this->addArgument('arguments', InputArgument::IS_ARRAY, 'Any additional argument will be passed to the test command.');
$this->addOption('launch-only', null, InputOption::VALUE_NONE, 'Only launches an instance and outputs the connection parameters. Useful if you want to connect via SSH.');
$this->addOption('update-only', null, InputOption::VALUE_NONE, 'Launches an instance, outputs the connection parameters and prepares the instance for a test run but does not actually run the tests. It will also checkout the specified version.');
- $this->addOption('one-instance-per-testsuite', null, InputOption::VALUE_NONE, 'Launches an instance, outputs the connection parameters and prepares the instance for a test run but does not actually run the tests. It will also checkout the specified version.');
+ $this->addOption('one-instance-per-testsuite', null, InputOption::VALUE_NONE, 'Launches one instance for system tests and one for ui tests.');
$this->addOption('checkout', null, InputOption::VALUE_REQUIRED, 'Git hash, tag or branch to checkout. Defaults to current hash', $this->getCurrentGitHash());
$this->addOption('patch-file', null, InputOption::VALUE_REQUIRED, 'Apply the given patch file after performing a checkout');
$this->setDescription('Run a specific testsuite on AWS');
@@ -57,15 +58,15 @@ If you want to apply a patch on top of the checked out version you can apply the
<comment>./console tests:run-aws --patch-file=test.patch ui</comment>
This will checkout the same revision as you are currently on and then apply the patch. To generate a diff use for instance the command <comment>git diff > test.patch</comment>.
This feature is still beta and there might be problems with pictures and/or binaries etc.
+
+You can also pass any argument to the command and they will be forwarded to the test command, for example to run a specific UI test: <comment>./console tests:run-aws ui Dashboard</comment>.
');
}
- /**
- * Execute command like: ./console core:clear-caches
- */
protected function execute(InputInterface $input, OutputInterface $output)
{
$testSuite = $this->getTestSuite($input);
+ $arguments = $input->getArgument('arguments');
$patchFile = $this->getPatchFile($input);
$launchOnly = $input->getOption('launch-only');
$updateOnly = $input->getOption('update-only');
@@ -102,7 +103,7 @@ This feature is still beta and there might be problems with pictures and/or bina
return 0;
}
- $testRunner->runTests($host, $testSuite);
+ $testRunner->runTests($host, $testSuite, $arguments);
$message = $this->buildFinishedMessage($testSuite, $host);
$output->writeln("\n$message\n");
diff --git a/plugins/TestRunner/Runner/Remote.php b/plugins/TestRunner/Runner/Remote.php
index c0a5c5d8e1..d85c4a268a 100644
--- a/plugins/TestRunner/Runner/Remote.php
+++ b/plugins/TestRunner/Runner/Remote.php
@@ -55,11 +55,11 @@ class Remote
}
}
- public function runTests($host, $testSuite)
+ public function runTests($host, $testSuite, array $arguments)
{
$this->prepareTestRun($host);
$this->printVersionInfo();
- $this->doRunTests($testSuite);
+ $this->doRunTests($testSuite, $arguments);
}
private function prepareTestRun($host)
@@ -74,17 +74,19 @@ class Remote
$this->ssh->exec('phantomjs --version');
}
- private function doRunTests($testSuite)
+ private function doRunTests($testSuite, array $arguments)
{
+ $arguments = implode(' ', $arguments);
+
$this->ssh->exec("ps -ef | grep \"php console tests:run\" | grep -v grep | awk '{print $2}' | xargs kill -9");
if ('all' === $testSuite) {
- $this->ssh->exec('php console tests:run --options="--colors"');
+ $this->ssh->exec('php console tests:run --options="--colors" ' . $arguments);
} elseif ('ui' === $testSuite) {
- $this->ssh->exec('php console tests:run-ui --persist-fixture-data --assume-artifacts');
+ $this->ssh->exec('php console tests:run-ui --persist-fixture-data --assume-artifacts ' . $arguments);
} else {
- $this->ssh->exec('php console tests:run --options="--colors" --testsuite="unit"');
- $this->ssh->exec('php console tests:run --options="--colors" --testsuite="' . $testSuite . '"');
+ $this->ssh->exec('php console tests:run --options="--colors" --testsuite="unit" ' . $arguments);
+ $this->ssh->exec('php console tests:run --options="--colors" --testsuite="' . $testSuite . '" ' . $arguments);
}
if ('system' === $testSuite) {
diff --git a/plugins/TestRunner/templates/travis.yml.twig b/plugins/TestRunner/templates/travis.yml.twig
index 1971674108..b70a9bf345 100644
--- a/plugins/TestRunner/templates/travis.yml.twig
+++ b/plugins/TestRunner/templates/travis.yml.twig
@@ -14,7 +14,7 @@ language: php
{% if phpVersions|default is empty %}
php:
- 5.6
- - 5.3
+ - 5.3.3
# - hhvm
{% else %}
php:
@@ -102,10 +102,6 @@ install:
- rm -rf plugins/$PLUGIN_NAME
- mv ../$PLUGIN_NAME plugins
- # copy .coveralls.yml if none exists
- - if [ ! -f ../coveralls.yml ];
- then cp .coveralls.yml ../coveralls.yml || true;
- fi
{% endif %}
# make sure travis test scripts are always latest (so in older releases/branches, the latest scripts will still be used)
@@ -125,11 +121,7 @@ before_script:
{% endif %}
- ./tests/travis/install_mysql_5.6.sh
- - if ([ -z "$TEST_SUITE" ] || [ -n "$PLUGIN_NAME" ]);
- then composer require satooshi/php-coveralls dev-master;
- else
- phpenv config-rm xdebug.ini;
- fi
+ - phpenv config-rm xdebug.ini;
# add always_populate_raw_post_data=-1 to php.ini
- echo "always_populate_raw_post_data=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
@@ -191,10 +183,6 @@ after_script:
# change directory back to root travis dir
- cd $PIWIK_ROOT_DIR
- - if ([ -z "$TEST_SUITE" ] || [ -n "$PLUGIN_NAME" ]);
- then php vendor/bin/coveralls -v;
- fi
-
# output contents of files w/ debugging info to screen
- cat /var/log/nginx/error.log
- cat $PIWIK_ROOT_DIR/tmp/php-fpm.log
diff --git a/plugins/TreemapVisualization b/plugins/TreemapVisualization
-Subproject 5dbb90f027b6d214aebfa4f222975d32e99d783
+Subproject 217f8298d5db252ceadd023ca409de1c66a051d
diff --git a/plugins/UserCountry/Columns/Country.php b/plugins/UserCountry/Columns/Country.php
index db8026ba6b..458e92b068 100644
--- a/plugins/UserCountry/Columns/Country.php
+++ b/plugins/UserCountry/Columns/Country.php
@@ -12,7 +12,7 @@ use Piwik\Common;
use Piwik\Config;
use Piwik\Container\StaticContainer;
use Piwik\Intl\Data\Provider\RegionDataProvider;
-use Piwik\IP;
+use Piwik\Network\IP;
use Piwik\Piwik;
use Piwik\Plugin\Manager;
use Piwik\Plugins\Provider\Provider as ProviderProvider;
@@ -107,12 +107,17 @@ class Country extends Base
/**
* Returns the hostname given the IP address string
*
- * @param string $ip IP Address
+ * @param string $ipStr IP Address
* @return string hostname (or human-readable IP address)
*/
- private function getHost($ip)
+ private function getHost($ipStr)
{
- return trim(strtolower(@IP::getHostByAddr($ip)));
+ $ip = IP::fromStringIP($ipStr);
+
+ $host = $ip->getHostname();
+ $host = ($host === null ? $ipStr : $host);
+
+ return trim(strtolower($host));
}
/**
diff --git a/plugins/VisitorGenerator b/plugins/VisitorGenerator
-Subproject 6a9cf2957920aa19b84ab10b348edbd80c58835
+Subproject 34d796330e256e947ff976f57e350c775dc061d