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 <diosmosis@users.noreply.github.com>2018-08-09 14:24:16 +0300
committerMatthieu Aubry <mattab@users.noreply.github.com>2018-08-09 14:24:16 +0300
commit2b77bb4d609dd0ec377a9edc32536f22dd4dabb2 (patch)
tree14e38fd0b07b26dbcf50dd2e25793b556d45baa7 /plugins/SegmentEditor
parent6112cc2ddf955b9c7183ba767e0a8acce93111ef (diff)
Add notification when report w/ segment has no data, but segment is unprocessed (#12823)3.6.0-b4
* When a report has no data, check if it is for an unprocessed segment and display an explanatory notification. * Remove transient notifications on reporting page change, allow datatable views to add notifications, use to display unprocessed segment message. * Update changelog. * Internationalize unprocessed segment message. * Parse notification divs in dashboardWidget.js when setting widget content. * Tweak message. * Change PR to use different approach: throw exception when no archives found and segment is used, then detect exception in new event. * Update changelog + document new event. * Unfinished review changes * more review fixes * Do not show notification w/ custom segments. * apply pr review * Apply review. * undo escaping since it was not needed & get test to pass * Different strategy + new test. * Fix tests. * Update two expected screenshots.
Diffstat (limited to 'plugins/SegmentEditor')
-rw-r--r--plugins/SegmentEditor/Model.php10
-rw-r--r--plugins/SegmentEditor/SegmentEditor.php133
-rw-r--r--plugins/SegmentEditor/UnprocessedSegmentException.php98
-rw-r--r--plugins/SegmentEditor/lang/en.json19
-rw-r--r--plugins/SegmentEditor/templates/_unprocessedSegmentMessage.twig18
-rw-r--r--plugins/SegmentEditor/tests/System/UnprocessedSegmentsTest.php226
-rw-r--r--plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentNoDataPreprocessed.xml14
-rw-r--r--plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentPreprocessed.xml14
-rw-r--r--plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentUnprocessed.xml4
-rw-r--r--plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_customSegmentPreprocessed.xml14
-rw-r--r--plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_customSegmentUnprocessed.xml4
-rw-r--r--plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_noLogDataSegmentUnprocessed.xml14
-rw-r--r--plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_noLogDataSegmentUnprocessedMultiSite.xml6
-rw-r--r--plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_realTimeSegmentUnprocessed.xml4
-rw-r--r--plugins/SegmentEditor/tests/UI/UnprocessedSegment_spec.js55
-rw-r--r--plugins/SegmentEditor/tests/UI/expected-screenshots/UnprocessedSegmentTest_custom_segment.png3
-rw-r--r--plugins/SegmentEditor/tests/UI/expected-screenshots/UnprocessedSegmentTest_unprocessed_segment.png3
17 files changed, 636 insertions, 3 deletions
diff --git a/plugins/SegmentEditor/Model.php b/plugins/SegmentEditor/Model.php
index 7e73b6a1ab..3aec99eb23 100644
--- a/plugins/SegmentEditor/Model.php
+++ b/plugins/SegmentEditor/Model.php
@@ -119,6 +119,15 @@ class Model
return $segments;
}
+ public function getSegmentByDefinition($definition)
+ {
+ $sql = $this->buildQuerySortedByName("definition = ?");
+ $bind = [$definition];
+
+ $segment = $this->getDb()->fetchRow($sql, $bind);
+ return $segment;
+ }
+
public function deleteSegment($idSegment)
{
$db = $this->getDb();
@@ -178,5 +187,4 @@ class Model
DbHelper::createTable(self::$rawPrefix, $segmentTable);
}
-
}
diff --git a/plugins/SegmentEditor/SegmentEditor.php b/plugins/SegmentEditor/SegmentEditor.php
index 9af29e2194..2ede0215a8 100644
--- a/plugins/SegmentEditor/SegmentEditor.php
+++ b/plugins/SegmentEditor/SegmentEditor.php
@@ -8,15 +8,29 @@
*/
namespace Piwik\Plugins\SegmentEditor;
+use Piwik\API\Request;
+use Piwik\ArchiveProcessor\Rules;
+use Piwik\Common;
use Piwik\Config;
use Piwik\Container\StaticContainer;
+use Piwik\DataAccess\ArchiveSelector;
+use Piwik\Notification;
use Piwik\Piwik;
use Piwik\Plugins\CoreHome\SystemSummary;
+use Piwik\Segment;
+use Piwik\SettingsPiwik;
+use Piwik\SettingsServer;
+use Piwik\Site;
+use Piwik\Period;
+use Piwik\Url;
+use Piwik\View;
/**
*/
class SegmentEditor extends \Piwik\Plugin
{
+ const NO_DATA_UNPROCESSED_SEGMENT_ID = 'nodata_segment_not_processed';
+
/**
* @see Piwik\Plugin::registerEvents
*/
@@ -30,6 +44,8 @@ class SegmentEditor extends \Piwik\Plugin
'Template.nextToCalendar' => 'getSegmentEditorHtml',
'System.addSystemSummaryItems' => 'addSystemSummaryItems',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
+ 'Visualization.onNoData' => 'onNoData',
+ 'Archive.noArchivedData' => 'onNoArchiveData',
);
}
@@ -71,6 +87,123 @@ class SegmentEditor extends \Piwik\Plugin
$segments = array_unique($segments);
}
+ public function onNoArchiveData()
+ {
+ // don't do check unless this is the root API request and it is an HTTP API request
+ if (!Request::isCurrentApiRequestTheRootApiRequest()
+ || !Request::isRootRequestApiRequest()
+ ) {
+ return null;
+ }
+
+ // don't do check during cron archiving
+ if (SettingsServer::isArchivePhpTriggered()) {
+ return null;
+ }
+
+ $segmentInfo = $this->getSegmentIfIsUnprocessed();
+ if (empty($segmentInfo)) {
+ return;
+ }
+
+ list($segment, $storedSegment, $isSegmentToPreprocess) = $segmentInfo;
+
+ throw new UnprocessedSegmentException($segment, $isSegmentToPreprocess, $storedSegment);
+ }
+
+ public function onNoData(View $dataTableView)
+ {
+ $segmentInfo = $this->getSegmentIfIsUnprocessed();
+ if (empty($segmentInfo)) {
+ return;
+ }
+
+ list($segment, $storedSegment, $isSegmentToPreprocess) = $segmentInfo;
+
+ if (!$isSegmentToPreprocess) {
+ return; // do not display the notification for custom segments
+ }
+
+ $segmentDisplayName = !empty($storedSegment['name']) ? $storedSegment['name'] : $segment;
+
+ $view = new View('@SegmentEditor/_unprocessedSegmentMessage.twig');
+ $view->isSegmentToPreprocess = $isSegmentToPreprocess;
+ $view->segmentName = $segmentDisplayName;
+ $view->visitorLogLink = '#' . Url::getCurrentQueryStringWithParametersModified([
+ 'category' => 'General_Visitors',
+ 'subcategory' => 'Live_VisitorLog',
+ ]);
+
+ $notification = new Notification($view->render());
+ $notification->priority = Notification::PRIORITY_HIGH;
+ $notification->context = Notification::CONTEXT_INFO;
+ $notification->flags = Notification::FLAG_NO_CLEAR;
+ $notification->type = Notification::TYPE_TRANSIENT;
+ $notification->raw = true;
+
+ $dataTableView->notifications[self::NO_DATA_UNPROCESSED_SEGMENT_ID] = $notification;
+ }
+
+ private function getSegmentIfIsUnprocessed()
+ {
+ // get idSites
+ $idSite = Common::getRequestVar('idSite', false);
+ if (empty($idSite)
+ || !is_numeric($idSite)
+ ) {
+ return null;
+ }
+
+ // get segment
+ $segment = Request::getRawSegmentFromRequest();
+ if (empty($segment)) {
+ return null;
+ }
+ $segment = new Segment($segment, [$idSite]);
+
+ // get period
+ $date = Common::getRequestVar('date', false);
+ $periodStr = Common::getRequestVar('period', false);
+ $period = Period\Factory::build($periodStr, $date);
+
+ // check if archiving is enabled. if so, the segment should have been processed.
+ $isArchivingDisabled = Rules::isArchivingDisabledFor([$idSite], $segment, $period);
+ if (!$isArchivingDisabled) {
+ return null;
+ }
+
+ // check if segment archive does not exist
+ $processorParams = new \Piwik\ArchiveProcessor\Parameters(new Site($idSite), $period, $segment);
+ $archiveIdAndStats = ArchiveSelector::getArchiveIdAndVisits($processorParams, null);
+ if (!empty($archiveIdAndStats[0])) {
+ return null;
+ }
+
+ $idSites = Site::getIdSitesFromIdSitesString($idSite);
+
+ if (strpos($date, ',') !== false) { // if getting multiple periods, check the whole range for visits
+ $periodStr = 'range';
+ }
+
+ // if no visits recorded, data will not appear, so don't show the message
+ $liveModel = new \Piwik\Plugins\Live\Model();
+ $visits = $liveModel->queryLogVisits($idSites, $periodStr, $date, $segment->getString(), $offset = 0, $limit = 1, null, null, 'ASC');
+ if (empty($visits)) {
+ return null;
+ }
+
+ // check if requested segment is segment to preprocess
+ $isSegmentToPreprocess = Rules::isSegmentPreProcessed([$idSite], $segment);
+
+ // this archive has no data, the report is for a segment that gets preprocessed, and the archive for this
+ // data does not exist. this means the data will be processed later. we let the user know so they will not
+ // be confused.
+ $model = new Model();
+ $storedSegment = $model->getSegmentByDefinition($segment->getString()) ?: null;
+
+ return [$segment, $storedSegment, $isSegmentToPreprocess];
+ }
+
public function install()
{
Model::install();
diff --git a/plugins/SegmentEditor/UnprocessedSegmentException.php b/plugins/SegmentEditor/UnprocessedSegmentException.php
new file mode 100644
index 0000000000..c0ddc338e2
--- /dev/null
+++ b/plugins/SegmentEditor/UnprocessedSegmentException.php
@@ -0,0 +1,98 @@
+<?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\SegmentEditor;
+
+
+use Piwik\Piwik;
+use Piwik\Segment;
+
+class UnprocessedSegmentException extends \Exception
+{
+ /**
+ * @var Segment
+ */
+ private $segment;
+
+ /**
+ * @var array|null
+ */
+ private $storedSegment;
+
+ /**
+ * @var bool
+ */
+ private $isSegmentToPreprocess;
+
+ /**
+ * @param $segment
+ */
+ public function __construct(Segment $segment, $isSegmentToPreprocess, array $storedSegment = null)
+ {
+ parent::__construct(self::getErrorMessage($segment, $isSegmentToPreprocess, $storedSegment));
+
+ $this->segment = $segment;
+ $this->storedSegment = $storedSegment;
+ $this->isSegmentToPreprocess = $isSegmentToPreprocess;
+ }
+
+ /**
+ * @return Segment
+ */
+ public function getSegment()
+ {
+ return $this->segment;
+ }
+
+ /**
+ * @return array|null
+ */
+ public function getStoredSegment()
+ {
+ return $this->storedSegment;
+ }
+
+ private static function getErrorMessage(Segment $segment, $isSegmentToPreprocess, array $storedSegment = null)
+ {
+ if (empty($storedSegment)) {
+ // the segment was not created through the segment editor
+ return Piwik::translate('SegmentEditor_CustomUnprocessedSegmentApiError1')
+ . ' ' . Piwik::translate('SegmentEditor_CustomUnprocessedSegmentApiError2')
+ . ' ' . Piwik::translate('SegmentEditor_CustomUnprocessedSegmentApiError3')
+ . ' ' . Piwik::translate('SegmentEditor_CustomUnprocessedSegmentApiError4')
+ . ' ' . Piwik::translate('SegmentEditor_CustomUnprocessedSegmentApiError5')
+ . ' ' . Piwik::translate('SegmentEditor_CustomUnprocessedSegmentApiError6')
+ . ' ' . Piwik::translate('SegmentEditor_UnprocessedSegmentInVisitorLog3');
+ }
+
+ $segmentName = !empty($storedSegment['name']) ? $storedSegment['name'] : $segment->getString();
+
+ if (!$isSegmentToPreprocess) {
+ // the segment was created in the segment editor, but set to be processed in real time
+ return Piwik::translate('SegmentEditor_UnprocessedSegmentApiError1', [$segmentName, Piwik::translate('SegmentEditor_AutoArchiveRealTime')])
+ . ' ' . Piwik::translate('SegmentEditor_UnprocessedSegmentApiError2', [Piwik::translate('SegmentEditor_AutoArchivePreProcessed')])
+ . ' ' . Piwik::translate('SegmentEditor_UnprocessedSegmentApiError3');
+ }
+
+ // the segment is set to be processed during cron archiving, but has not been processed yet
+ return Piwik::translate('SegmentEditor_UnprocessedSegmentNoData1', ['(' . $segmentName . ')'])
+ . ' ' . Piwik::translate('SegmentEditor_UnprocessedSegmentNoData2')
+ . ' ' . Piwik::translate('SegmentEditor_CustomUnprocessedSegmentApiError5')
+ . ' ' . Piwik::translate('SegmentEditor_CustomUnprocessedSegmentApiError6')
+ . ' ' . Piwik::translate('SegmentEditor_UnprocessedSegmentInVisitorLog3');
+ }
+
+ /**
+ * @return bool
+ */
+ public function isSegmentToPreprocess()
+ {
+ return $this->isSegmentToPreprocess;
+ }
+} \ No newline at end of file
diff --git a/plugins/SegmentEditor/lang/en.json b/plugins/SegmentEditor/lang/en.json
index 1ea1eb8bae..b2ba38c07e 100644
--- a/plugins/SegmentEditor/lang/en.json
+++ b/plugins/SegmentEditor/lang/en.json
@@ -22,7 +22,7 @@
"SegmentDisplayedThisWebsiteOnly": "this website only",
"SegmentIsDisplayedForWebsite": "and processed for",
"SegmentNotApplied": "Segment '%s' not applied",
- "SegmentNotAppliedMessage": "You are requesting data for the Custom Segment '%s', this Matomo configuration currently prevents real time processing of reports for performance reasons.",
+ "SegmentNotAppliedMessage": "You are requesting data for the Custom Segment '%s', this Matomo's configuration currently prevents real time processing of reports for performance reasons.",
"SelectSegmentOfVisits": "Select a segment of visits:",
"ThisSegmentIsVisibleTo": "This segment is visible to:",
"VisibleToAllUsers": "all users",
@@ -36,6 +36,21 @@
"SegmentXIsAUnionOf": "%s is a union of these segments:",
"CustomSegment": "Custom Segment",
"SegmentOperatorIsNullOrEmpty": "is null or empty",
- "SegmentOperatorIsNotNullNorEmpty": "is not null nor empty"
+ "SegmentOperatorIsNotNullNorEmpty": "is not null nor empty",
+ "UnprocessedSegmentNoData1": "These reports have no data, because the Segment you requested %1$s has not yet been processed by the system.",
+ "UnprocessedSegmentNoData2": "Data for this Segment should become available in a few hours when processing completes. (If it does not, there may be a problem.)",
+ "UnprocessedSegmentInVisitorLog1": "%1$sMeanwhile you can use the Visitor Log%2$s to test whether your segment will match your users correctly by applying it there.",
+ "UnprocessedSegmentInVisitorLog2": "When applied, you can see immediately which visits and actions were matched by your segment.",
+ "UnprocessedSegmentInVisitorLog3": "This can help you confirm your Segment matches the users and actions you expect it to.",
+ "UnprocessedSegmentApiError1": "The Segment '%1$s' is set to '%2$s' but Matomo is not currently configured to process segmented reports in API requests.",
+ "UnprocessedSegmentApiError2": "To see data for this report in the future, you will need to edit your segment and choose the option labeled '%s'.",
+ "UnprocessedSegmentApiError3": "Then after a few hours your segment data should become available through the API. (If it does not, there may be a problem.)",
+ "CustomUnprocessedSegmentApiError1": "The Segment you requested has not yet been created in the Segment Editor and so the report data has not been pre-processed.",
+ "CustomUnprocessedSegmentApiError2": "To see data for this segment, you must go to Matomo and create this segment manually in the Segment Editor.",
+ "CustomUnprocessedSegmentApiError3": "(Alternatively, you can create a new segment programatically using the SegmentEditor.add API method).",
+ "CustomUnprocessedSegmentApiError4": "Once created the segment in the editor (or via API), this error message will disappear and within a few hours you will see your segmented report data, after the segment data has been pre-processed. (If it does not, there may be a problem.)",
+ "CustomUnprocessedSegmentApiError5": "Please note that you can test whether your segment will work without having to wait for it to be processed by using the Live.getLastVisitsDetails API.",
+ "CustomUnprocessedSegmentApiError6": "When using this API method, you will see which users and actions were matched by your &segment= parameter.",
+ "CustomUnprocessedSegmentNoData": "To see data for this segment, you must create this segment manually in the Segment Editor, then wait a couple hours for preprocessing to complete."
}
} \ No newline at end of file
diff --git a/plugins/SegmentEditor/templates/_unprocessedSegmentMessage.twig b/plugins/SegmentEditor/templates/_unprocessedSegmentMessage.twig
new file mode 100644
index 0000000000..4c8891dfde
--- /dev/null
+++ b/plugins/SegmentEditor/templates/_unprocessedSegmentMessage.twig
@@ -0,0 +1,18 @@
+{% set visitorLogLinkHtml %}<a href="{{ visitorLogLink }}" target="_blank">{% endset %}
+{% if isSegmentToPreprocess %}
+<p>
+ {{ 'SegmentEditor_UnprocessedSegmentNoData1'|translate('<strong>(' ~ segmentName ~ ')</strong>')|raw }}
+ {{ 'SegmentEditor_UnprocessedSegmentNoData2'|translate }}
+</p>
+{% else %}
+<p>
+ {{ 'SegmentEditor_CustomUnprocessedSegmentApiError1'|translate }}
+ {{ 'SegmentEditor_CustomUnprocessedSegmentNoData'|translate }}
+</p>
+{% endif %}
+<p>&nbsp;</p>
+<p>
+ {{ 'SegmentEditor_UnprocessedSegmentInVisitorLog1'|translate(visitorLogLinkHtml, '</a>')|raw }}
+ {{ 'SegmentEditor_UnprocessedSegmentInVisitorLog2'|translate }}
+ {{ 'SegmentEditor_UnprocessedSegmentInVisitorLog3'|translate }}
+</p> \ No newline at end of file
diff --git a/plugins/SegmentEditor/tests/System/UnprocessedSegmentsTest.php b/plugins/SegmentEditor/tests/System/UnprocessedSegmentsTest.php
new file mode 100644
index 0000000000..e4d3d45c17
--- /dev/null
+++ b/plugins/SegmentEditor/tests/System/UnprocessedSegmentsTest.php
@@ -0,0 +1,226 @@
+<?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\SegmentEditor\tests\System;
+
+use Piwik\ArchiveProcessor\Rules;
+use Piwik\Common;
+use Piwik\Config;
+use Piwik\Date;
+use Piwik\Db;
+use Piwik\Plugins\SegmentEditor\API;
+use Piwik\Plugins\VisitsSummary;
+use Piwik\Tests\Fixtures\OneVisitorTwoVisits;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+
+/**
+ * @group SegmentEditor
+ * @group System
+ * @group UnprocessedSegmentsTest
+ */
+class UnprocessedSegmentsTest extends IntegrationTestCase
+{
+ /**
+ * @var OneVisitorTwoVisits
+ */
+ public static $fixture;
+
+ const TEST_SEGMENT = 'browserCode==ff';
+
+ public function test_apiOutput_whenCustomSegmentUsed_WithBrowserArchivingDisabled()
+ {
+ Rules::setBrowserTriggerArchiving(false);
+
+ $segments = Rules::getSegmentsToProcess([self::$fixture->idSite]);
+ $this->assertNotContains(self::TEST_SEGMENT, $segments);
+
+ $this->runAnyApiTest('VisitsSummary.get', 'customSegmentUnprocessed', [
+ 'idSite' => self::$fixture->idSite,
+ 'date' => Date::factory(self::$fixture->dateTime)->toString(),
+ 'period' => 'week',
+ 'segment' => self::TEST_SEGMENT,
+ ]);
+ }
+
+ public function test_apiOutput_whenRealTimeProcessedSegmentUsed_WithBrowserArchivingDisabled()
+ {
+ $idSegment = API::getInstance()->add('testsegment', self::TEST_SEGMENT, self::$fixture->idSite, $autoArchive = false);
+
+ $storedSegment = API::getInstance()->get($idSegment);
+ $this->assertNotEmpty($storedSegment);
+
+ Rules::setBrowserTriggerArchiving(false);
+
+ $segments = Rules::getSegmentsToProcess([self::$fixture->idSite]);
+ $this->assertNotContains(self::TEST_SEGMENT, $segments);
+
+ $this->runAnyApiTest('VisitsSummary.get', 'realTimeSegmentUnprocessed', [
+ 'idSite' => self::$fixture->idSite,
+ 'date' => Date::factory(self::$fixture->dateTime)->toString(),
+ 'period' => 'week',
+ 'segment' => self::TEST_SEGMENT,
+ ]);
+ }
+
+ public function test_apiOutput_whenUnprocessedAutoArchiveSegmentUsed_WithBrowserArchivingDisabled()
+ {
+ $idSegment = API::getInstance()->add('testsegment', self::TEST_SEGMENT, self::$fixture->idSite, $autoArchive = true);
+
+ $storedSegment = API::getInstance()->get($idSegment);
+ $this->assertNotEmpty($storedSegment);
+
+ Rules::setBrowserTriggerArchiving(false);
+
+ $segments = Rules::getSegmentsToProcess([self::$fixture->idSite]);
+ $this->assertContains(self::TEST_SEGMENT, $segments);
+
+ $this->runAnyApiTest('VisitsSummary.get', 'autoArchiveSegmentUnprocessed', [
+ 'idSite' => self::$fixture->idSite,
+ 'date' => Date::factory(self::$fixture->dateTime)->toString(),
+ 'period' => 'week',
+ 'segment' => self::TEST_SEGMENT,
+ ]);
+ }
+
+ public function test_apiOutput_whenPreprocessedSegmentUsed_WithBrowserArchivingDisabled()
+ {
+ $idSegment = API::getInstance()->add('testsegment', self::TEST_SEGMENT, self::$fixture->idSite, $autoArchive = true);
+
+ $storedSegment = API::getInstance()->get($idSegment);
+ $this->assertNotEmpty($storedSegment);
+
+ VisitsSummary\API::getInstance()->get(self::$fixture->idSite, 'week',
+ Date::factory(self::$fixture->dateTime)->toString(), self::TEST_SEGMENT); // archive
+
+ Rules::setBrowserTriggerArchiving(false);
+
+ $segments = Rules::getSegmentsToProcess([self::$fixture->idSite]);
+ $this->assertContains(self::TEST_SEGMENT, $segments);
+
+ $this->runAnyApiTest('VisitsSummary.get', 'autoArchiveSegmentPreprocessed', [
+ 'idSite' => self::$fixture->idSite,
+ 'date' => Date::factory(self::$fixture->dateTime)->toString(),
+ 'period' => 'week',
+ 'segment' => self::TEST_SEGMENT,
+ ]);
+ }
+
+ public function test_apiOutput_whenPreprocessedCustomSegmentUsed_WithBrowserArchivingDisabled()
+ {
+ VisitsSummary\API::getInstance()->get(self::$fixture->idSite, 'week',
+ Date::factory(self::$fixture->dateTime)->toString(), self::TEST_SEGMENT); // archive
+
+ Rules::setBrowserTriggerArchiving(false);
+
+ $segments = Rules::getSegmentsToProcess([self::$fixture->idSite]);
+ $this->assertNotContains(self::TEST_SEGMENT, $segments);
+
+ $this->runAnyApiTest('VisitsSummary.get', 'customSegmentPreprocessed', [
+ 'idSite' => self::$fixture->idSite,
+ 'date' => Date::factory(self::$fixture->dateTime)->toString(),
+ 'period' => 'week',
+ 'segment' => self::TEST_SEGMENT,
+ ]);
+ }
+
+ public function test_apiOutput_whenPreprocessedSegmentUsed_WithNoData_AndBrowserArchivingDisabled()
+ {
+ $this->clearLogData();
+
+ $idSegment = API::getInstance()->add('testsegment', self::TEST_SEGMENT, self::$fixture->idSite, $autoArchive = true);
+
+ $storedSegment = API::getInstance()->get($idSegment);
+ $this->assertNotEmpty($storedSegment);
+
+ VisitsSummary\API::getInstance()->get(self::$fixture->idSite, 'week',
+ Date::factory(self::$fixture->dateTime)->toString(), self::TEST_SEGMENT); // archive
+
+ Rules::setBrowserTriggerArchiving(false);
+
+ $segments = Rules::getSegmentsToProcess([self::$fixture->idSite]);
+ $this->assertContains(self::TEST_SEGMENT, $segments);
+
+ $this->runAnyApiTest('VisitsSummary.get', 'autoArchiveSegmentNoDataPreprocessed', [
+ 'idSite' => self::$fixture->idSite,
+ 'date' => Date::factory(self::$fixture->dateTime)->toString(),
+ 'period' => 'week',
+ 'segment' => self::TEST_SEGMENT,
+ ]);
+ }
+
+ public function test_apiOutput_whenNoLogDataAndUnprocessedSegmentUsed_AndBrowserArchivingDisabled()
+ {
+ $this->clearLogData();
+
+ $idSegment = API::getInstance()->add('testsegment', self::TEST_SEGMENT, self::$fixture->idSite, $autoArchive = true);
+
+ $storedSegment = API::getInstance()->get($idSegment);
+ $this->assertNotEmpty($storedSegment);
+
+ Rules::setBrowserTriggerArchiving(false);
+
+ $segments = Rules::getSegmentsToProcess([self::$fixture->idSite]);
+ $this->assertContains(self::TEST_SEGMENT, $segments);
+
+ $this->runAnyApiTest('VisitsSummary.get', 'noLogDataSegmentUnprocessed', [
+ 'idSite' => self::$fixture->idSite,
+ 'date' => Date::factory(self::$fixture->dateTime)->toString(),
+ 'period' => 'week',
+ 'segment' => self::TEST_SEGMENT,
+ ]);
+ }
+
+ public function test_apiOutput_whenMultipleSitesRequested_OneWithDataOneNot_AndBrowserArchivingDisabled()
+ {
+ $idSegment = API::getInstance()->add('testsegment', self::TEST_SEGMENT, $idSite = false, $autoArchive = true);
+
+ $storedSegment = API::getInstance()->get($idSegment);
+ $this->assertNotEmpty($storedSegment);
+
+ Rules::setBrowserTriggerArchiving(false);
+
+ $segments = Rules::getSegmentsToProcess([self::$fixture->idSite]);
+ $this->assertContains(self::TEST_SEGMENT, $segments);
+
+ $this->runAnyApiTest('VisitsSummary.get', 'noLogDataSegmentUnprocessedMultiSite', [
+ 'idSite' => 'all',
+ 'date' => Date::factory(self::$fixture->dateTime)->toString(),
+ 'period' => 'week',
+ 'segment' => self::TEST_SEGMENT,
+ ]);
+ }
+
+ public static function getOutputPrefix()
+ {
+ return '';
+ }
+
+ public static function getPathToTestDirectory()
+ {
+ return dirname(__FILE__);
+ }
+
+ public function provideContainerConfig()
+ {
+ return [
+ Config::class => \DI\decorate(function (Config $previous) {
+ $previous->General['browser_archiving_disabled_enforce'] = 1;
+ return $previous;
+ }),
+ ];
+ }
+
+ private function clearLogData()
+ {
+ Db::query('TRUNCATE ' . Common::prefixTable('log_visit'));
+ Db::query('TRUNCATE ' . Common::prefixTable('log_link_visit_action'));
+ Db::query('TRUNCATE ' . Common::prefixTable('log_conversion'));
+ }
+}
+
+UnprocessedSegmentsTest::$fixture = new OneVisitorTwoVisits();
diff --git a/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentNoDataPreprocessed.xml b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentNoDataPreprocessed.xml
new file mode 100644
index 0000000000..32b66284be
--- /dev/null
+++ b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentNoDataPreprocessed.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <nb_uniq_visitors>0</nb_uniq_visitors>
+ <nb_users>0</nb_users>
+ <nb_visits>0</nb_visits>
+ <nb_actions>0</nb_actions>
+ <nb_visits_converted>0</nb_visits_converted>
+ <bounce_count>0</bounce_count>
+ <sum_visit_length>0</sum_visit_length>
+ <max_actions>0</max_actions>
+ <bounce_rate>0%</bounce_rate>
+ <nb_actions_per_visit>0</nb_actions_per_visit>
+ <avg_time_on_site>0</avg_time_on_site>
+</result> \ No newline at end of file
diff --git a/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentPreprocessed.xml b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentPreprocessed.xml
new file mode 100644
index 0000000000..c8a2c198e8
--- /dev/null
+++ b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentPreprocessed.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_users>0</nb_users>
+ <nb_visits>2</nb_visits>
+ <nb_actions>8</nb_actions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <bounce_count>1</bounce_count>
+ <sum_visit_length>1621</sum_visit_length>
+ <max_actions>7</max_actions>
+ <bounce_rate>50%</bounce_rate>
+ <nb_actions_per_visit>4</nb_actions_per_visit>
+ <avg_time_on_site>811</avg_time_on_site>
+</result> \ No newline at end of file
diff --git a/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentUnprocessed.xml b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentUnprocessed.xml
new file mode 100644
index 0000000000..57b75e01db
--- /dev/null
+++ b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_autoArchiveSegmentUnprocessed.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <error message="These reports have no data, because the Segment you requested (testsegment) has not yet been processed by the system. Data for this Segment should become available in a few hours when processing completes. (If it does not, there may be a problem.) Please note that you can test whether your segment will work without having to wait for it to be processed by using the Live.getLastVisitsDetails API. When using this API method, you will see which users and actions were matched by your &amp;segment= parameter. This can help you confirm your Segment matches the users and actions you expect it to." />
+</result> \ No newline at end of file
diff --git a/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_customSegmentPreprocessed.xml b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_customSegmentPreprocessed.xml
new file mode 100644
index 0000000000..c8a2c198e8
--- /dev/null
+++ b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_customSegmentPreprocessed.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_users>0</nb_users>
+ <nb_visits>2</nb_visits>
+ <nb_actions>8</nb_actions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <bounce_count>1</bounce_count>
+ <sum_visit_length>1621</sum_visit_length>
+ <max_actions>7</max_actions>
+ <bounce_rate>50%</bounce_rate>
+ <nb_actions_per_visit>4</nb_actions_per_visit>
+ <avg_time_on_site>811</avg_time_on_site>
+</result> \ No newline at end of file
diff --git a/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_customSegmentUnprocessed.xml b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_customSegmentUnprocessed.xml
new file mode 100644
index 0000000000..ed4fec1ebd
--- /dev/null
+++ b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_customSegmentUnprocessed.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <error message="The Segment you requested has not yet been created in the Segment Editor and so the report data has not been pre-processed. To see data for this segment, you must go to Matomo and create this segment manually in the Segment Editor. (Alternatively, you can create a new segment programatically using the SegmentEditor.add API method). Once created the segment in the editor (or via API), this error message will disappear and within a few hours you will see your segmented report data, after the segment data has been pre-processed. (If it does not, there may be a problem.) Please note that you can test whether your segment will work without having to wait for it to be processed by using the Live.getLastVisitsDetails API. When using this API method, you will see which users and actions were matched by your &amp;segment= parameter. This can help you confirm your Segment matches the users and actions you expect it to." />
+</result> \ No newline at end of file
diff --git a/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_noLogDataSegmentUnprocessed.xml b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_noLogDataSegmentUnprocessed.xml
new file mode 100644
index 0000000000..32b66284be
--- /dev/null
+++ b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_noLogDataSegmentUnprocessed.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <nb_uniq_visitors>0</nb_uniq_visitors>
+ <nb_users>0</nb_users>
+ <nb_visits>0</nb_visits>
+ <nb_actions>0</nb_actions>
+ <nb_visits_converted>0</nb_visits_converted>
+ <bounce_count>0</bounce_count>
+ <sum_visit_length>0</sum_visit_length>
+ <max_actions>0</max_actions>
+ <bounce_rate>0%</bounce_rate>
+ <nb_actions_per_visit>0</nb_actions_per_visit>
+ <avg_time_on_site>0</avg_time_on_site>
+</result> \ No newline at end of file
diff --git a/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_noLogDataSegmentUnprocessedMultiSite.xml b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_noLogDataSegmentUnprocessedMultiSite.xml
new file mode 100644
index 0000000000..dd52dc4ff4
--- /dev/null
+++ b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_noLogDataSegmentUnprocessedMultiSite.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<results>
+ <result idSite="1" />
+ <result idSite="2" />
+ <result idSite="3" />
+</results> \ No newline at end of file
diff --git a/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_realTimeSegmentUnprocessed.xml b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_realTimeSegmentUnprocessed.xml
new file mode 100644
index 0000000000..0dcab5ab6d
--- /dev/null
+++ b/plugins/SegmentEditor/tests/System/expected/test___VisitsSummary.get_realTimeSegmentUnprocessed.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <error message="The Segment 'testsegment' is set to 'segmented reports are processed in real time' but Matomo is not currently configured to process segmented reports in API requests. To see data for this report in the future, you will need to edit your segment and choose the option labeled 'segmented reports are pre-processed (faster, requires cron)'. Then after a few hours your segment data should become available through the API. (If it does not, there may be a problem.)" />
+</result> \ No newline at end of file
diff --git a/plugins/SegmentEditor/tests/UI/UnprocessedSegment_spec.js b/plugins/SegmentEditor/tests/UI/UnprocessedSegment_spec.js
new file mode 100644
index 0000000000..5278471cba
--- /dev/null
+++ b/plugins/SegmentEditor/tests/UI/UnprocessedSegment_spec.js
@@ -0,0 +1,55 @@
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * SegmentEditor screenshot tests.
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+describe("UnprocessedSegmentTest", function () {
+ this.fixture = 'Piwik\\Tests\\Fixtures\\OneVisitorTwoVisits';
+ this.timeout(0);
+
+ var generalParams = 'idSite=1&period=day&date=2010-03-06';
+ var segment = 'browserCode==ff';
+ var customSegment = 'languageCode==fr';
+ var url = '?module=CoreHome&action=index&' + generalParams + '#?' + generalParams + '&category=General_Visitors&subcategory=General_Overview';
+
+ before(function (done) {
+ testEnvironment.callApi('SegmentEditor.add', {
+ name: '<script>alert("testsegment");</script>',
+ definition: segment,
+ idSite: 1,
+ autoArchive: 1,
+ enableAllUsers: 1,
+ }, done);
+ });
+
+ before(function () {
+ testEnvironment.configOverride.General = {
+ browser_archiving_disabled_enforce: '1',
+ enable_browser_archiving_triggering: '0',
+ };
+ testEnvironment.optionsOverride = {
+ enableBrowserTriggerArchiving: '0',
+ };
+ testEnvironment.save();
+ });
+
+ after(function (done) {
+ testEnvironment.callApi('SegmentEditor.delete', { idSegment: 1 }, done);
+ });
+
+ it("should show a notification for unprocessed segments", function (done) {
+ expect.screenshot("unprocessed_segment").to.be.captureSelector('.pageWrap', function (page) {
+ page.load(url + '&segment=' + encodeURIComponent(segment));
+ }, done);
+ });
+
+ it('should not show a notification for custom segments that are not preprocessed', function (done) {
+ expect.screenshot("custom_segment").to.be.captureSelector('.pageWrap', function (page) {
+ page.load(url + '&segment=' + encodeURIComponent(customSegment));
+ }, done);
+ });
+});
diff --git a/plugins/SegmentEditor/tests/UI/expected-screenshots/UnprocessedSegmentTest_custom_segment.png b/plugins/SegmentEditor/tests/UI/expected-screenshots/UnprocessedSegmentTest_custom_segment.png
new file mode 100644
index 0000000000..542460805d
--- /dev/null
+++ b/plugins/SegmentEditor/tests/UI/expected-screenshots/UnprocessedSegmentTest_custom_segment.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6f90e885887d8623ebfcc63ecb641aa1b4cee70c718194fb22d183dc275c0ed5
+size 60004
diff --git a/plugins/SegmentEditor/tests/UI/expected-screenshots/UnprocessedSegmentTest_unprocessed_segment.png b/plugins/SegmentEditor/tests/UI/expected-screenshots/UnprocessedSegmentTest_unprocessed_segment.png
new file mode 100644
index 0000000000..35c4aa46b7
--- /dev/null
+++ b/plugins/SegmentEditor/tests/UI/expected-screenshots/UnprocessedSegmentTest_unprocessed_segment.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:568747c15966b58fa0242c94e91bf0d8e33d4f19609d2b7053cc3487a1d6e8a8
+size 104572