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:
authorThomas Steur <thomas.steur@gmail.com>2016-08-29 07:01:46 +0300
committerThomas Steur <thomas.steur@gmail.com>2016-08-29 07:01:46 +0300
commit4c9d1274408fb57d5e0b53dcda425dc4892c7b00 (patch)
tree78b0f24058d586cdd109de0387d43165e112003e /plugins/UserId
parent0c9c30b731ccbacf47e154b9f7a590af49e3d799 (diff)
parent4b395d2385e0041973349c7575fc10378b85558e (diff)
Merge branch 'master' into 3.0-m06
Conflicts: .travis.yml bower.json core/Notification/Manager.php core/Updates.php core/Updates/2.16.2-b2.php core/Version.php libs/Zend/Validate/Hostname.php libs/bower_components/jScrollPane/ajax.html libs/bower_components/jScrollPane/anchors.html libs/bower_components/jScrollPane/api.html libs/bower_components/jScrollPane/arrow_hover.html libs/bower_components/jScrollPane/arrow_positions.html libs/bower_components/jScrollPane/arrows.html libs/bower_components/jScrollPane/auto_reinitialise.html libs/bower_components/jScrollPane/basic.html libs/bower_components/jScrollPane/caps.html libs/bower_components/jScrollPane/changelog.html libs/bower_components/jScrollPane/destroy.html libs/bower_components/jScrollPane/drag_size.html libs/bower_components/jScrollPane/dynamic_content.html libs/bower_components/jScrollPane/dynamic_height.html libs/bower_components/jScrollPane/dynamic_width.html libs/bower_components/jScrollPane/events.html libs/bower_components/jScrollPane/faqs.html libs/bower_components/jScrollPane/fixed_width.html libs/bower_components/jScrollPane/focus.html libs/bower_components/jScrollPane/fullpage_scroll.html libs/bower_components/jScrollPane/iframe.html libs/bower_components/jScrollPane/iframe2.html libs/bower_components/jScrollPane/iframe_content1.html libs/bower_components/jScrollPane/iframe_content2.html libs/bower_components/jScrollPane/image.html libs/bower_components/jScrollPane/image2.html libs/bower_components/jScrollPane/index.html libs/bower_components/jScrollPane/invisibles.html libs/bower_components/jScrollPane/known_issues.html libs/bower_components/jScrollPane/less_basic.html libs/bower_components/jScrollPane/mwheel_intent.html libs/bower_components/jScrollPane/override_animate.html libs/bower_components/jScrollPane/runeimp.html libs/bower_components/jScrollPane/runeimp2.html libs/bower_components/jScrollPane/scroll_on_left.html libs/bower_components/jScrollPane/scroll_to.html libs/bower_components/jScrollPane/scroll_to_animate.html libs/bower_components/jScrollPane/settings.html libs/bower_components/jScrollPane/short.html libs/bower_components/jquery/.bower.json libs/bower_components/jquery/LICENSE.txt libs/bower_components/jquery/dist/jquery.js libs/bower_components/jquery/dist/jquery.min.js libs/bower_components/jquery/dist/jquery.min.map libs/bower_components/jquery/sizzle/dist/sizzle.js libs/bower_components/jquery/src/ajax.js libs/bower_components/jquery/src/ajax/jsonp.js libs/bower_components/jquery/src/ajax/load.js libs/bower_components/jquery/src/ajax/parseJSON.js libs/bower_components/jquery/src/ajax/parseXML.js libs/bower_components/jquery/src/ajax/script.js libs/bower_components/jquery/src/ajax/xhr.js libs/bower_components/jquery/src/attributes/attr.js libs/bower_components/jquery/src/attributes/classes.js libs/bower_components/jquery/src/attributes/prop.js libs/bower_components/jquery/src/attributes/support.js libs/bower_components/jquery/src/attributes/val.js libs/bower_components/jquery/src/callbacks.js libs/bower_components/jquery/src/core.js libs/bower_components/jquery/src/core/access.js libs/bower_components/jquery/src/core/init.js libs/bower_components/jquery/src/core/parseHTML.js libs/bower_components/jquery/src/core/ready.js libs/bower_components/jquery/src/css.js libs/bower_components/jquery/src/css/curCSS.js libs/bower_components/jquery/src/css/hiddenVisibleSelectors.js libs/bower_components/jquery/src/css/support.js libs/bower_components/jquery/src/css/var/swap.js libs/bower_components/jquery/src/data.js libs/bower_components/jquery/src/data/accepts.js libs/bower_components/jquery/src/deferred.js libs/bower_components/jquery/src/deprecated.js libs/bower_components/jquery/src/dimensions.js libs/bower_components/jquery/src/effects.js libs/bower_components/jquery/src/effects/Tween.js libs/bower_components/jquery/src/event.js libs/bower_components/jquery/src/event/support.js libs/bower_components/jquery/src/manipulation.js libs/bower_components/jquery/src/manipulation/support.js libs/bower_components/jquery/src/offset.js libs/bower_components/jquery/src/queue.js libs/bower_components/jquery/src/serialize.js libs/bower_components/jquery/src/traversing.js libs/bower_components/jquery/src/traversing/findFilter.js libs/bower_components/jquery/src/var/concat.js libs/bower_components/jquery/src/var/indexOf.js libs/bower_components/jquery/src/var/push.js libs/bower_components/jquery/src/var/slice.js libs/bower_components/jquery/src/wrap.js plugins/API/ProcessedReport.php plugins/AnonymousPiwikUsageMeasurement plugins/CoreConsole/Commands/ManagePlugin.php plugins/CoreHome/javascripts/dataTable.js plugins/CoreHome/javascripts/manifest.json plugins/CoreHome/templates/_topBar.twig plugins/CoreUpdater/templates/updateSuccess.twig plugins/CustomAlerts plugins/CustomDimensions plugins/DevicesDetection/Reports/GetBrowserVersions.php plugins/DevicesDetection/Reports/GetBrowsers.php plugins/ExamplePlugin/Updates/0.0.2.php plugins/Feedback/templates/index.twig plugins/LogViewer plugins/Morpheus/stylesheets/general/_forms.less plugins/Morpheus/templates/layout.twig plugins/Morpheus/templates/user.twig plugins/QueuedTracking plugins/SegmentEditor/stylesheets/segmentation.less plugins/SitesManager/tests/Integration/ApiTest.php tests/PHPUnit/Integration/WidgetsListTest.php tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html tests/UI/expected-ui-screenshots tests/UI/specs/SegmentSelectorEditor_spec.js
Diffstat (limited to 'plugins/UserId')
-rw-r--r--plugins/UserId/.gitignore1
-rw-r--r--plugins/UserId/API.php46
-rw-r--r--plugins/UserId/Archiver.php140
-rw-r--r--plugins/UserId/Columns/UserId.php29
-rw-r--r--plugins/UserId/Reports/Base.php19
-rw-r--r--plugins/UserId/Reports/GetUsers.php72
-rw-r--r--plugins/UserId/UserId.php53
-rw-r--r--plugins/UserId/images/visitordetails-hover.pngbin0 -> 1275 bytes
-rw-r--r--plugins/UserId/images/visitordetails.pngbin0 -> 1273 bytes
-rw-r--r--plugins/UserId/javascripts/rowaction.js74
-rw-r--r--plugins/UserId/lang/am.json5
-rw-r--r--plugins/UserId/lang/ar.json5
-rw-r--r--plugins/UserId/lang/be.json5
-rw-r--r--plugins/UserId/lang/bg.json5
-rw-r--r--plugins/UserId/lang/ca.json5
-rw-r--r--plugins/UserId/lang/cs.json7
-rw-r--r--plugins/UserId/lang/da.json5
-rw-r--r--plugins/UserId/lang/de.json7
-rw-r--r--plugins/UserId/lang/el.json7
-rw-r--r--plugins/UserId/lang/en.json7
-rw-r--r--plugins/UserId/lang/es.json5
-rw-r--r--plugins/UserId/lang/et.json5
-rw-r--r--plugins/UserId/lang/eu.json5
-rw-r--r--plugins/UserId/lang/fa.json5
-rw-r--r--plugins/UserId/lang/fi.json5
-rw-r--r--plugins/UserId/lang/fr.json7
-rw-r--r--plugins/UserId/lang/gl.json5
-rw-r--r--plugins/UserId/lang/he.json5
-rw-r--r--plugins/UserId/lang/hi.json5
-rw-r--r--plugins/UserId/lang/hr.json5
-rw-r--r--plugins/UserId/lang/hu.json5
-rw-r--r--plugins/UserId/lang/id.json5
-rw-r--r--plugins/UserId/lang/is.json5
-rw-r--r--plugins/UserId/lang/it.json7
-rw-r--r--plugins/UserId/lang/ja.json5
-rw-r--r--plugins/UserId/lang/ka.json5
-rw-r--r--plugins/UserId/lang/ko.json5
-rw-r--r--plugins/UserId/lang/lt.json5
-rw-r--r--plugins/UserId/lang/lv.json5
-rw-r--r--plugins/UserId/lang/nb.json7
-rw-r--r--plugins/UserId/lang/nl.json7
-rw-r--r--plugins/UserId/lang/nn.json5
-rw-r--r--plugins/UserId/lang/pl.json5
-rw-r--r--plugins/UserId/lang/pt-br.json7
-rw-r--r--plugins/UserId/lang/pt.json5
-rw-r--r--plugins/UserId/lang/ro.json5
-rw-r--r--plugins/UserId/lang/ru.json5
-rw-r--r--plugins/UserId/lang/sk.json5
-rw-r--r--plugins/UserId/lang/sl.json5
-rw-r--r--plugins/UserId/lang/sq.json5
-rw-r--r--plugins/UserId/lang/sr.json5
-rw-r--r--plugins/UserId/lang/sv.json7
-rw-r--r--plugins/UserId/lang/ta.json5
-rw-r--r--plugins/UserId/lang/te.json5
-rw-r--r--plugins/UserId/lang/th.json5
-rw-r--r--plugins/UserId/lang/tl.json5
-rw-r--r--plugins/UserId/lang/tr.json5
-rw-r--r--plugins/UserId/lang/uk.json5
-rw-r--r--plugins/UserId/lang/vi.json7
-rw-r--r--plugins/UserId/lang/zh-cn.json5
-rw-r--r--plugins/UserId/lang/zh-tw.json5
-rw-r--r--plugins/UserId/tests/Fixtures/TrackFewVisitsAndCreateUsers.php58
-rw-r--r--plugins/UserId/tests/System/ApiTest.php154
-rw-r--r--plugins/UserId/tests/System/expected/test___UserId.getUsers_day.xml39
-rw-r--r--plugins/UserId/tests/System/expected/test___UserId.getUsers_range.xml39
-rw-r--r--plugins/UserId/tests/System/expected/test_ascSortOrder__UserId.getUsers_day.xml39
-rw-r--r--plugins/UserId/tests/System/expected/test_ascSortOrder__UserId.getUsers_range.xml39
-rw-r--r--plugins/UserId/tests/System/expected/test_limit__UserId.getUsers_day.xml27
-rw-r--r--plugins/UserId/tests/System/expected/test_limit__UserId.getUsers_range.xml27
-rw-r--r--plugins/UserId/tests/System/expected/test_searchByUserId__UserId.getUsers_day.xml15
-rw-r--r--plugins/UserId/tests/System/expected/test_searchByUserId__UserId.getUsers_range.xml15
71 files changed, 1163 insertions, 0 deletions
diff --git a/plugins/UserId/.gitignore b/plugins/UserId/.gitignore
new file mode 100644
index 0000000000..c8c9480010
--- /dev/null
+++ b/plugins/UserId/.gitignore
@@ -0,0 +1 @@
+tests/System/processed/*xml \ No newline at end of file
diff --git a/plugins/UserId/API.php b/plugins/UserId/API.php
new file mode 100644
index 0000000000..932e19b113
--- /dev/null
+++ b/plugins/UserId/API.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\UserId;
+
+use Piwik\Archive;
+use Piwik\Metrics;
+use Piwik\Piwik;
+use Piwik\DataTable;
+use Piwik\DataTable\Row;
+
+/**
+ * API for plugin UserId. Allows to get User IDs table.
+ *
+ * @method static \Piwik\Plugins\UserId\API getInstance()
+ */
+class API extends \Piwik\Plugin\API
+{
+ /**
+ * Get a report of all User Ids.
+ *
+ * @param int $idSite
+ *
+ * @param string $period
+ * @param int $date
+ * @param string|bool $segment
+ *
+ * @return DataTable
+ */
+ public function getUsers($idSite, $period, $date, $segment = false)
+ {
+ Piwik::checkUserHasViewAccess($idSite);
+ $archive = Archive::build($idSite, $period, $date, $segment);
+ $dataTable = $archive->getDataTable(Archiver::USERID_ARCHIVE_RECORD);
+
+ $dataTable->queueFilter('ReplaceColumnNames');
+ $dataTable->queueFilter('ReplaceSummaryRowLabel');
+
+ return $dataTable;
+ }
+}
diff --git a/plugins/UserId/Archiver.php b/plugins/UserId/Archiver.php
new file mode 100644
index 0000000000..28c32bf3c6
--- /dev/null
+++ b/plugins/UserId/Archiver.php
@@ -0,0 +1,140 @@
+<?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\UserId;
+use Piwik\Config;
+use Piwik\DataArray;
+use Piwik\DataTable;
+use Piwik\Metrics;
+
+/**
+ * Archiver that aggregates metrics per user ID (user_id field).
+ */
+class Archiver extends \Piwik\Plugin\Archiver
+{
+ const USERID_ARCHIVE_RECORD = "UserId_users";
+
+ const VISITOR_ID_FIELD = 'idvisitor';
+ const USER_ID_FIELD = 'user_id';
+
+ protected $maximumRowsInDataTableLevelZero;
+
+ function __construct($processor)
+ {
+ parent::__construct($processor);
+
+ $this->maximumRowsInDataTableLevelZero = Config::getInstance()->General['datatable_archiving_maximum_rows_userid_users'];
+ }
+
+ /**
+ * @var DataArray
+ */
+ protected $arrays;
+
+ /**
+ * Array to save visitor IDs for every user ID met during archiving process. We use it to
+ * fill metadata before actual inserting rows to DB.
+ * @var array
+ */
+ protected $visitorIdsUserIdsMap = array();
+
+ /**
+ * Archives data for a day period.
+ */
+ public function aggregateDayReport()
+ {
+ $this->arrays = new DataArray();
+ $this->aggregateUsers();
+ $this->insertDayReports();
+ }
+ /**
+ * Period archiving: simply sums up daily archives
+ */
+ public function aggregateMultipleReports()
+ {
+ $dataTableRecords = array(self::USERID_ARCHIVE_RECORD);
+ $columnsAggregationOperation = null;
+ $this->getProcessor()->aggregateDataTableRecords(
+ $dataTableRecords,
+ $this->maximumRowsInDataTableLevelZero,
+ $this->maximumRowsInDataTableLevelZero,
+ $columnToSort = 'nb_visits',
+ $columnsAggregationOperation,
+ $columnsToRenameAfterAggregation = null,
+ $countRowsRecursive = array());
+ }
+
+ /**
+ * Used to aggregate daily data per user ID
+ */
+ protected function aggregateUsers()
+ {
+ $userIdFieldName = self::USER_ID_FIELD;
+ $visitorIdFieldName = self::VISITOR_ID_FIELD;
+
+ /** @var \Zend_Db_Statement $query */
+ $query = $this->getLogAggregator()->queryVisitsByDimension(
+ array(self::USER_ID_FIELD),
+ "$userIdFieldName IS NOT NULL AND $userIdFieldName != ''",
+ array("LOWER(HEX($visitorIdFieldName)) as $visitorIdFieldName")
+ );
+
+ if ($query === false) {
+ return;
+ }
+
+ $rowsCount = 0;
+ while ($row = $query->fetch()) {
+ $rowsCount++;
+ $this->arrays->sumMetricsVisits($row[$userIdFieldName], $row);
+ $this->rememberVisitorId($row);
+ }
+ }
+
+ /**
+ * Insert aggregated daily data serialized
+ *
+ * @throws \Exception
+ */
+ protected function insertDayReports()
+ {
+ /** @var DataTable $dataTable */
+ $dataTable = $this->arrays->asDataTable();
+ $this->setVisitorIds($dataTable);
+ $report = $dataTable->getSerialized($this->maximumRowsInDataTableLevelZero, null, Metrics::INDEX_NB_VISITS);
+ $this->getProcessor()->insertBlobRecord(self::USERID_ARCHIVE_RECORD, $report);
+ }
+
+ /**
+ * Remember visitor ID per user. We use it to fill metadata before actual inserting rows to DB.
+ *
+ * @param array $row
+ */
+ private function rememberVisitorId($row)
+ {
+ if (!empty($row[self::USER_ID_FIELD]) && !empty($row[self::VISITOR_ID_FIELD])) {
+ $this->visitorIdsUserIdsMap[$row[self::USER_ID_FIELD]] = $row[self::VISITOR_ID_FIELD];
+ }
+ }
+
+ /**
+ * Fill visitor ID as metadata before actual inserting rows to DB.
+ *
+ * @param DataTable $dataTable
+ */
+ private function setVisitorIds(DataTable $dataTable)
+ {
+ foreach ($dataTable->getRows() as $row) {
+ $userId = $row->getColumn('label');
+ if (isset($this->visitorIdsUserIdsMap[$userId])) {
+ $row->setMetadata(self::VISITOR_ID_FIELD, $this->visitorIdsUserIdsMap[$userId]);
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/plugins/UserId/Columns/UserId.php b/plugins/UserId/Columns/UserId.php
new file mode 100644
index 0000000000..7ac474cf73
--- /dev/null
+++ b/plugins/UserId/Columns/UserId.php
@@ -0,0 +1,29 @@
+<?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\UserId\Columns;
+
+use Piwik\Piwik;
+use Piwik\Plugin\Dimension\VisitDimension;
+
+/**
+ * UserId dimension
+ */
+class UserId extends VisitDimension
+{
+
+ /**
+ * The name of the dimension which will be visible for instance in the UI of a related report and in the mobile app.
+ * @return string
+ */
+ public function getName()
+ {
+ return Piwik::translate('UserId_UserId');
+ }
+
+} \ No newline at end of file
diff --git a/plugins/UserId/Reports/Base.php b/plugins/UserId/Reports/Base.php
new file mode 100644
index 0000000000..aa3f70e197
--- /dev/null
+++ b/plugins/UserId/Reports/Base.php
@@ -0,0 +1,19 @@
+<?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\UserId\Reports;
+
+use Piwik\Plugin\Report;
+
+abstract class Base extends Report
+{
+ protected function init()
+ {
+ $this->categoryId = 'General_Visitors';
+ }
+}
diff --git a/plugins/UserId/Reports/GetUsers.php b/plugins/UserId/Reports/GetUsers.php
new file mode 100644
index 0000000000..776c29e02f
--- /dev/null
+++ b/plugins/UserId/Reports/GetUsers.php
@@ -0,0 +1,72 @@
+<?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\UserId\Reports;
+
+use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+use Piwik\Plugins\UserId\Columns\UserId;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
+
+/**
+ * A report showing all unique user IDs and some aggregated information about them. It also allows
+ * to open a popover with visitor details
+ */
+class GetUsers extends Base
+{
+ protected function init()
+ {
+ parent::init();
+
+ $this->name = Piwik::translate('UserId_UserReportTitle');
+ $this->subcategoryId = 'UserId_UserReportTitle';
+ $this->documentation = '';
+ $this->dimension = new UserId();
+ $this->metrics = array('label', 'nb_visits', 'nb_actions', 'nb_visits_converted');
+
+ // This defines in which order your report appears in the mobile app, in the menu and in the list of widgets
+ $this->order = 9;
+ }
+
+ /**
+ * @return array
+ */
+ public static function getColumnsToDisplay()
+ {
+ return array();
+ }
+
+ /**
+ * @param ViewDataTable $view
+ */
+ public function configureView(ViewDataTable $view)
+ {
+ $view->config->addTranslation('label', Piwik::translate('General_UserId'));
+ $view->config->addTranslation('nb_visits_converted', Piwik::translate('General_VisitConvertedGoal'));
+
+ /*
+ * Hide most of the table footer actions, leaving only export icons and pagination
+ */
+ $view->config->columns_to_display = $this->metrics;
+ $view->config->show_all_views_icons = false;
+ $view->config->show_active_view_icon = false;
+ $view->config->show_related_reports = false;
+ $view->config->show_insights = false;
+ $view->config->show_pivot_by_subtable = false;
+ $view->config->show_flatten_table = false;
+
+ if ($view->isViewDataTableId(HtmlTable::ID)) {
+ $view->config->disable_row_evolution = false;
+ }
+
+ // exclude users with less then 2 visits, when low population filter is active
+ $view->requestConfig->filter_excludelowpop_value = 2;
+ }
+}
diff --git a/plugins/UserId/UserId.php b/plugins/UserId/UserId.php
new file mode 100644
index 0000000000..b69f47c4e7
--- /dev/null
+++ b/plugins/UserId/UserId.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\UserId;
+
+use Piwik\Db;
+
+/**
+ * Plugin adds a new Users report showing all unique user IDs and some aggregated data
+ */
+class UserId extends \Piwik\Plugin
+{
+ /**
+ * Register event observers
+ *
+ * @return array
+ */
+ public function registerEvents()
+ {
+ return array(
+ // Add plugin's custom JS files
+ 'AssetManager.getJavaScriptFiles' => 'getJavaScriptFiles',
+ // Add translations for the client side JS
+ 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
+ );
+ }
+
+ /**
+ * Add a custom JS to the page. It adds possibility to open visitor details popover for each
+ * user ID in a report table
+ *
+ * @param $jsFiles
+ */
+ public function getJavaScriptFiles(&$jsFiles)
+ {
+ $jsFiles[] = "plugins/UserId/javascripts/rowaction.js";
+ }
+
+ /**
+ * Add translations for the client side JS
+ *
+ * @param $translationKeys
+ */
+ public function getClientSideTranslationKeys(&$translationKeys)
+ {
+ $translationKeys[] = "Live_ViewVisitorProfile";
+ }
+}
diff --git a/plugins/UserId/images/visitordetails-hover.png b/plugins/UserId/images/visitordetails-hover.png
new file mode 100644
index 0000000000..523a8ac6b4
--- /dev/null
+++ b/plugins/UserId/images/visitordetails-hover.png
Binary files differ
diff --git a/plugins/UserId/images/visitordetails.png b/plugins/UserId/images/visitordetails.png
new file mode 100644
index 0000000000..423392db75
--- /dev/null
+++ b/plugins/UserId/images/visitordetails.png
Binary files differ
diff --git a/plugins/UserId/javascripts/rowaction.js b/plugins/UserId/javascripts/rowaction.js
new file mode 100644
index 0000000000..d100c1f3f5
--- /dev/null
+++ b/plugins/UserId/javascripts/rowaction.js
@@ -0,0 +1,74 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * This file registers the visitor details overlay row action on the user IDs list page.
+ */
+(function () {
+
+ var actionName = 'visitorDetails';
+
+ function DataTable_RowActions_VisitorDetails(dataTable) {
+ this.dataTable = dataTable;
+ this.actionName = actionName;
+ this.trEventName = 'piwikTriggerVisitorDetailsAction';
+ }
+
+ DataTable_RowActions_VisitorDetails.prototype = new DataTable_RowAction();
+
+ DataTable_RowActions_VisitorDetails.prototype.performAction = function (label, tr, e) {
+ var visitorId = this.getRowMetadata($(tr)).idvisitor || '';
+ visitorId = encodeURIComponent(visitorId);
+ if (visitorId.length > 0) {
+ DataTable_RowAction.prototype.openPopover.apply(this, ['module=Live&action=getVisitorProfilePopup&visitorId=' + visitorId]);
+ }
+ };
+
+ DataTable_RowActions_VisitorDetails.prototype.doOpenPopover = function (urlParam) {
+ Piwik_Popover.createPopupAndLoadUrl(urlParam, _pk_translate('Live_VisitorProfile'), 'visitor-profile-popup');
+ };
+
+ DataTable_RowActions_Registry.register({
+
+ name: actionName,
+
+ instance: null,
+
+ dataTableIcon: 'plugins/UserId/images/visitordetails.png',
+ dataTableIconHover: 'plugins/UserId/images/visitordetails-hover.png',
+
+ order: 30,
+
+ dataTableIconTooltip: [
+ _pk_translate('Live_ViewVisitorProfile'),
+ ''
+ ],
+
+ isAvailableOnReport: function (dataTableParams, undefined) {
+ return dataTableParams.module == 'UserId';
+ },
+
+ isAvailableOnRow: function (dataTableParams, tr) {
+ return DataTable_RowAction.prototype.getRowMetadata(tr).hasOwnProperty('idvisitor');
+ },
+
+ createInstance: function (dataTable, param) {
+ if (dataTable !== null && typeof dataTable.visitorDetailsInstance != 'undefined') {
+ return dataTable.segmentVisitorLogInstance;
+ }
+
+ var instance = new DataTable_RowActions_VisitorDetails(dataTable);
+ if (dataTable !== null) {
+ dataTable.visitorDetailsInstance = instance;
+ }
+
+ this.instance = instance;
+
+ return instance;
+ }
+ });
+})(); \ No newline at end of file
diff --git a/plugins/UserId/lang/am.json b/plugins/UserId/lang/am.json
new file mode 100644
index 0000000000..89b16469da
--- /dev/null
+++ b/plugins/UserId/lang/am.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "ተጠቃሚዎች"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/ar.json b/plugins/UserId/lang/ar.json
new file mode 100644
index 0000000000..20c6e62bdb
--- /dev/null
+++ b/plugins/UserId/lang/ar.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "المستخدمون"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/be.json b/plugins/UserId/lang/be.json
new file mode 100644
index 0000000000..db19effcfb
--- /dev/null
+++ b/plugins/UserId/lang/be.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Карыстачы"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/bg.json b/plugins/UserId/lang/bg.json
new file mode 100644
index 0000000000..2265cef2c2
--- /dev/null
+++ b/plugins/UserId/lang/bg.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Потребители"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/ca.json b/plugins/UserId/lang/ca.json
new file mode 100644
index 0000000000..ef7056f9df
--- /dev/null
+++ b/plugins/UserId/lang/ca.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Usuaris"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/cs.json b/plugins/UserId/lang/cs.json
new file mode 100644
index 0000000000..e5e54b8aaf
--- /dev/null
+++ b/plugins/UserId/lang/cs.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "UserId",
+ "UserReportTitle": "Uživatelé",
+ "PluginDescription": "Zobrazí reporty uživatel"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/da.json b/plugins/UserId/lang/da.json
new file mode 100644
index 0000000000..399a31080b
--- /dev/null
+++ b/plugins/UserId/lang/da.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Brugere"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/de.json b/plugins/UserId/lang/de.json
new file mode 100644
index 0000000000..d2543cfcbf
--- /dev/null
+++ b/plugins/UserId/lang/de.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "Benutzer-ID",
+ "UserReportTitle": "Benutzer",
+ "PluginDescription": "Zeigt Benutzer-Berichte"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/el.json b/plugins/UserId/lang/el.json
new file mode 100644
index 0000000000..f9ffd5b451
--- /dev/null
+++ b/plugins/UserId/lang/el.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "Αναγνωριστικό χρήστη",
+ "UserReportTitle": "Χρήστες",
+ "PluginDescription": "Εμφανίζει τις αναφορές χρηστών"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/en.json b/plugins/UserId/lang/en.json
new file mode 100644
index 0000000000..40d9f3660d
--- /dev/null
+++ b/plugins/UserId/lang/en.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "UserId",
+ "UserReportTitle": "Users",
+ "PluginDescription": "Shows user reports"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/es.json b/plugins/UserId/lang/es.json
new file mode 100644
index 0000000000..98b725a25a
--- /dev/null
+++ b/plugins/UserId/lang/es.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Usuarios"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/et.json b/plugins/UserId/lang/et.json
new file mode 100644
index 0000000000..0777e69781
--- /dev/null
+++ b/plugins/UserId/lang/et.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Kasutajaid"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/eu.json b/plugins/UserId/lang/eu.json
new file mode 100644
index 0000000000..9e73f162f5
--- /dev/null
+++ b/plugins/UserId/lang/eu.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Erabiltzaileak"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/fa.json b/plugins/UserId/lang/fa.json
new file mode 100644
index 0000000000..e1a99adfe3
--- /dev/null
+++ b/plugins/UserId/lang/fa.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "کاربران"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/fi.json b/plugins/UserId/lang/fi.json
new file mode 100644
index 0000000000..72950a6649
--- /dev/null
+++ b/plugins/UserId/lang/fi.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Käyttäjät"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/fr.json b/plugins/UserId/lang/fr.json
new file mode 100644
index 0000000000..f0ec8c6d8d
--- /dev/null
+++ b/plugins/UserId/lang/fr.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "UserId",
+ "UserReportTitle": "Utilisateurs",
+ "PluginDescription": "Affiche les rapports utilisateur"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/gl.json b/plugins/UserId/lang/gl.json
new file mode 100644
index 0000000000..617065bb0d
--- /dev/null
+++ b/plugins/UserId/lang/gl.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Usuario"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/he.json b/plugins/UserId/lang/he.json
new file mode 100644
index 0000000000..35c16ba1e9
--- /dev/null
+++ b/plugins/UserId/lang/he.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "משתמשים"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/hi.json b/plugins/UserId/lang/hi.json
new file mode 100644
index 0000000000..a03ecf9b7c
--- /dev/null
+++ b/plugins/UserId/lang/hi.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "उपयोगकर्ता"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/hr.json b/plugins/UserId/lang/hr.json
new file mode 100644
index 0000000000..9f34d4a7cb
--- /dev/null
+++ b/plugins/UserId/lang/hr.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Korisnici"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/hu.json b/plugins/UserId/lang/hu.json
new file mode 100644
index 0000000000..afd68b2ac8
--- /dev/null
+++ b/plugins/UserId/lang/hu.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Felhasználók"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/id.json b/plugins/UserId/lang/id.json
new file mode 100644
index 0000000000..67985af03f
--- /dev/null
+++ b/plugins/UserId/lang/id.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Pengguna"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/is.json b/plugins/UserId/lang/is.json
new file mode 100644
index 0000000000..b5af86b45e
--- /dev/null
+++ b/plugins/UserId/lang/is.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Notendur"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/it.json b/plugins/UserId/lang/it.json
new file mode 100644
index 0000000000..ec2e4beb8d
--- /dev/null
+++ b/plugins/UserId/lang/it.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "Id Utente",
+ "UserReportTitle": "Utenti",
+ "PluginDescription": "Mostra i report utente"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/ja.json b/plugins/UserId/lang/ja.json
new file mode 100644
index 0000000000..b1c2060004
--- /dev/null
+++ b/plugins/UserId/lang/ja.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "ユーザー"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/ka.json b/plugins/UserId/lang/ka.json
new file mode 100644
index 0000000000..b1db014206
--- /dev/null
+++ b/plugins/UserId/lang/ka.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "მომხმარებლები"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/ko.json b/plugins/UserId/lang/ko.json
new file mode 100644
index 0000000000..e68c34e7f2
--- /dev/null
+++ b/plugins/UserId/lang/ko.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "사용자"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/lt.json b/plugins/UserId/lang/lt.json
new file mode 100644
index 0000000000..9d60aaa439
--- /dev/null
+++ b/plugins/UserId/lang/lt.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Naudotojai"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/lv.json b/plugins/UserId/lang/lv.json
new file mode 100644
index 0000000000..630778b101
--- /dev/null
+++ b/plugins/UserId/lang/lv.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Lietotāji"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/nb.json b/plugins/UserId/lang/nb.json
new file mode 100644
index 0000000000..b8404858f2
--- /dev/null
+++ b/plugins/UserId/lang/nb.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "Bruker-ID",
+ "UserReportTitle": "Brukere",
+ "PluginDescription": "Vises brukerrapporter"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/nl.json b/plugins/UserId/lang/nl.json
new file mode 100644
index 0000000000..7c4446cd64
--- /dev/null
+++ b/plugins/UserId/lang/nl.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "Gebruikers-ID",
+ "UserReportTitle": "Gebruikers",
+ "PluginDescription": "Toont gebruikerrapporten"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/nn.json b/plugins/UserId/lang/nn.json
new file mode 100644
index 0000000000..fd50467a5c
--- /dev/null
+++ b/plugins/UserId/lang/nn.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Brukarar"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/pl.json b/plugins/UserId/lang/pl.json
new file mode 100644
index 0000000000..3372d2057a
--- /dev/null
+++ b/plugins/UserId/lang/pl.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Użytkownicy"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/pt-br.json b/plugins/UserId/lang/pt-br.json
new file mode 100644
index 0000000000..43e1b12fec
--- /dev/null
+++ b/plugins/UserId/lang/pt-br.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "UserId",
+ "UserReportTitle": "Usuários",
+ "PluginDescription": "Mostra relatórios de usuários"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/pt.json b/plugins/UserId/lang/pt.json
new file mode 100644
index 0000000000..f0724879a7
--- /dev/null
+++ b/plugins/UserId/lang/pt.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Utilizadores"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/ro.json b/plugins/UserId/lang/ro.json
new file mode 100644
index 0000000000..c6670264b2
--- /dev/null
+++ b/plugins/UserId/lang/ro.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Utilizatori"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/ru.json b/plugins/UserId/lang/ru.json
new file mode 100644
index 0000000000..353190053a
--- /dev/null
+++ b/plugins/UserId/lang/ru.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Пользователи"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/sk.json b/plugins/UserId/lang/sk.json
new file mode 100644
index 0000000000..be0f5fbf12
--- /dev/null
+++ b/plugins/UserId/lang/sk.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Používatelia"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/sl.json b/plugins/UserId/lang/sl.json
new file mode 100644
index 0000000000..6a3b1959d6
--- /dev/null
+++ b/plugins/UserId/lang/sl.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Uporabniki"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/sq.json b/plugins/UserId/lang/sq.json
new file mode 100644
index 0000000000..2c8c14380c
--- /dev/null
+++ b/plugins/UserId/lang/sq.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Përdorues"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/sr.json b/plugins/UserId/lang/sr.json
new file mode 100644
index 0000000000..9f34d4a7cb
--- /dev/null
+++ b/plugins/UserId/lang/sr.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Korisnici"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/sv.json b/plugins/UserId/lang/sv.json
new file mode 100644
index 0000000000..98e102901d
--- /dev/null
+++ b/plugins/UserId/lang/sv.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "Användar ID",
+ "UserReportTitle": "Användare",
+ "PluginDescription": "Visa användarrapporter"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/ta.json b/plugins/UserId/lang/ta.json
new file mode 100644
index 0000000000..b8b8e7ec01
--- /dev/null
+++ b/plugins/UserId/lang/ta.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "பாவனையாளர்கள்"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/te.json b/plugins/UserId/lang/te.json
new file mode 100644
index 0000000000..57139b029a
--- /dev/null
+++ b/plugins/UserId/lang/te.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "వాడుకరులు"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/th.json b/plugins/UserId/lang/th.json
new file mode 100644
index 0000000000..850ec2b335
--- /dev/null
+++ b/plugins/UserId/lang/th.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "ผู้ใช้"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/tl.json b/plugins/UserId/lang/tl.json
new file mode 100644
index 0000000000..9c7f9b544f
--- /dev/null
+++ b/plugins/UserId/lang/tl.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Users"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/tr.json b/plugins/UserId/lang/tr.json
new file mode 100644
index 0000000000..9aec350fb0
--- /dev/null
+++ b/plugins/UserId/lang/tr.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Kullanıcılar"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/uk.json b/plugins/UserId/lang/uk.json
new file mode 100644
index 0000000000..6ecfc09fe4
--- /dev/null
+++ b/plugins/UserId/lang/uk.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "Користувачі"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/vi.json b/plugins/UserId/lang/vi.json
new file mode 100644
index 0000000000..5fa38b3ff8
--- /dev/null
+++ b/plugins/UserId/lang/vi.json
@@ -0,0 +1,7 @@
+{
+ "UserId": {
+ "UserId": "ID người dùng",
+ "UserReportTitle": "Các người dùng",
+ "PluginDescription": "Hiển thị báo cáo người dùng"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/zh-cn.json b/plugins/UserId/lang/zh-cn.json
new file mode 100644
index 0000000000..b6bdb6f51d
--- /dev/null
+++ b/plugins/UserId/lang/zh-cn.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "用户管理"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/lang/zh-tw.json b/plugins/UserId/lang/zh-tw.json
new file mode 100644
index 0000000000..35697dc6fd
--- /dev/null
+++ b/plugins/UserId/lang/zh-tw.json
@@ -0,0 +1,5 @@
+{
+ "UserId": {
+ "UserReportTitle": "使用者"
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/tests/Fixtures/TrackFewVisitsAndCreateUsers.php b/plugins/UserId/tests/Fixtures/TrackFewVisitsAndCreateUsers.php
new file mode 100644
index 0000000000..3c5ac0fcbd
--- /dev/null
+++ b/plugins/UserId/tests/Fixtures/TrackFewVisitsAndCreateUsers.php
@@ -0,0 +1,58 @@
+<?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\UserId\tests\Fixtures;
+
+use Piwik\Date;
+use Piwik\Plugins\UserId\API;
+use Piwik\Tests\Framework\Fixture;
+
+/**
+ * Generates visits with user IDs and creates the user IDs index for testing
+ */
+class TrackFewVisitsAndCreateUsers extends Fixture
+{
+ public $dateTime = '2010-02-01 11:22:33';
+ public $idSite = 1;
+
+ public function setUp()
+ {
+ if (!self::siteCreated($idSite = 1)) {
+ self::createWebsite($this->dateTime);
+ }
+
+ $this->trackVisits();
+ }
+
+ private function trackVisits()
+ {
+ $t = self::getTracker($this->idSite, $this->dateTime, $defaultInit = true);
+ $t->setTokenAuth(self::getTokenAuth());
+ $t->enableBulkTracking();
+
+ foreach (array('user1', 'user2', 'user3') as $key => $userId) {
+ for ($numVisits = 0; $numVisits < ($key+1) * 10; $numVisits++) {
+ $t->setUserId($userId);
+ if ($numVisits % 5 == 0) {
+ $t->doTrackSiteSearch('some search term');
+ }
+ if ($numVisits % 4 == 0) {
+ $t->doTrackEvent('Event action', 'event cat');
+ }
+ $t->setForceNewVisit();
+ $t->setUrl('http://example.org/my/dir/page' . ($numVisits % 4));
+
+ $visitDateTime = Date::factory($this->dateTime)->addDay($numVisits)->getDatetime();
+ $t->setForceVisitDateTime($visitDateTime);
+
+ self::assertTrue($t->doTrackPageView('incredible title ' . ($numVisits % 3)));
+ }
+ }
+
+ self::checkBulkTrackingResponse($t->doBulkTrack());
+ }
+} \ No newline at end of file
diff --git a/plugins/UserId/tests/System/ApiTest.php b/plugins/UserId/tests/System/ApiTest.php
new file mode 100644
index 0000000000..ca73c2792d
--- /dev/null
+++ b/plugins/UserId/tests/System/ApiTest.php
@@ -0,0 +1,154 @@
+<?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\UserId\tests\System;
+
+use Piwik\Plugins\UserId\tests\Fixtures\TrackFewVisitsAndCreateUsers;
+use Piwik\Tests\Framework\TestCase\SystemTestCase;
+
+/**
+ * Run system tests against the UserId.getUsers API method
+ *
+ * @group UserId
+ * @group ApiTest
+ * @group Plugins
+ */
+class ApiTest extends SystemTestCase
+{
+ /**
+ * @var TrackFewVisitsAndCreateUsers
+ */
+ public static $fixture;
+
+ /**
+ * @dataProvider getApiForTesting
+ */
+ public function testApi($api, $params)
+ {
+ $this->runApiTests($api, $params);
+ }
+
+ public function getApiForTesting()
+ {
+ $api = 'UserId.getUsers';
+ $startDate = substr(self::$fixture->dateTime, 0, 10);
+ $endDate = date('Y-m-d', strtotime($startDate) + 3600*24*365);
+
+ $apiToTest = array();
+ $apiToTest[] = array(
+ $api,
+ array(
+ 'date' => $startDate,
+ 'periods' => array('day'),
+ 'idSite' => 1,
+ 'testSuffix' => ''
+ )
+ );
+ $apiToTest[] = array(
+ $api,
+ array(
+ 'date' => "$startDate,$endDate",
+ 'periods' => array('range'),
+ 'idSite' => 1,
+ 'testSuffix' => ''
+ )
+ );
+
+ $apiToTest[] = array(
+ $api,
+ array(
+ 'date' => $startDate,
+ 'periods' => array('day'),
+ 'idSite' => 1,
+ 'testSuffix' => 'limit',
+ 'otherRequestParameters' => array(
+ 'filter_limit' => '2',
+ 'filter_offset' => '1',
+ )
+ )
+ );
+ $apiToTest[] = array(
+ $api,
+ array(
+ 'date' => "$startDate,$endDate",
+ 'periods' => array('range'),
+ 'idSite' => 1,
+ 'testSuffix' => 'limit',
+ 'otherRequestParameters' => array(
+ 'filter_limit' => '2',
+ 'filter_offset' => '1',
+ )
+ )
+ );
+
+ $apiToTest[] = array(
+ $api,
+ array(
+ 'date' => $startDate,
+ 'periods' => array('day'),
+ 'idSite' => 1,
+ 'testSuffix' => 'ascSortOrder',
+ 'otherRequestParameters' => array(
+ 'filter_sort_order' => 'asc',
+ )
+ )
+ );
+ $apiToTest[] = array(
+ $api,
+ array(
+ 'date' => "$startDate,$endDate",
+ 'periods' => array('range'),
+ 'idSite' => 1,
+ 'testSuffix' => 'ascSortOrder',
+ 'otherRequestParameters' => array(
+ 'filter_sort_order' => 'asc',
+ )
+ )
+ );
+
+ $apiToTest[] = array(
+ $api,
+ array(
+ 'date' => $startDate,
+ 'periods' => array('day'),
+ 'idSite' => 1,
+ 'testSuffix' => 'searchByUserId',
+ 'otherRequestParameters' => array(
+ 'filter_pattern' => 'user2'
+ )
+ )
+ );
+ $apiToTest[] = array(
+ $api,
+ array(
+ 'date' => "$startDate,$endDate",
+ 'periods' => array('range'),
+ 'idSite' => 1,
+ 'testSuffix' => 'searchByUserId',
+ 'otherRequestParameters' => array(
+ 'filter_pattern' => 'user2'
+ )
+ )
+ );
+
+ return $apiToTest;
+ }
+
+ public static function getOutputPrefix()
+ {
+ return '';
+ }
+
+ public static function getPathToTestDirectory()
+ {
+ return dirname(__FILE__);
+ }
+
+}
+
+ApiTest::$fixture = new TrackFewVisitsAndCreateUsers(); \ No newline at end of file
diff --git a/plugins/UserId/tests/System/expected/test___UserId.getUsers_day.xml b/plugins/UserId/tests/System/expected/test___UserId.getUsers_day.xml
new file mode 100644
index 0000000000..19e7d78d39
--- /dev/null
+++ b/plugins/UserId/tests/System/expected/test___UserId.getUsers_day.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>user1</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_actions>3</nb_actions>
+ <nb_users>1</nb_users>
+ <max_actions>2</max_actions>
+ <sum_visit_length>1</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <idvisitor>b3daa77b4c04a955</idvisitor>
+ </row>
+ <row>
+ <label>user2</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>1</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <idvisitor>a1881c06eec96db9</idvisitor>
+ </row>
+ <row>
+ <label>user3</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>1</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <idvisitor>0b7f849446d33835</idvisitor>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserId/tests/System/expected/test___UserId.getUsers_range.xml b/plugins/UserId/tests/System/expected/test___UserId.getUsers_range.xml
new file mode 100644
index 0000000000..184a718ff4
--- /dev/null
+++ b/plugins/UserId/tests/System/expected/test___UserId.getUsers_range.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>user3</label>
+ <nb_visits>31</nb_visits>
+ <nb_actions>44</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>12</sum_visit_length>
+ <bounce_count>19</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>30</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>30</sum_daily_nb_users>
+ <idvisitor>0b7f849446d33835</idvisitor>
+ </row>
+ <row>
+ <label>user2</label>
+ <nb_visits>21</nb_visits>
+ <nb_actions>29</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>8</sum_visit_length>
+ <bounce_count>13</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>20</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>20</sum_daily_nb_users>
+ <idvisitor>a1881c06eec96db9</idvisitor>
+ </row>
+ <row>
+ <label>user1</label>
+ <nb_visits>11</nb_visits>
+ <nb_actions>15</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>7</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>10</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>10</sum_daily_nb_users>
+ <idvisitor>b3daa77b4c04a955</idvisitor>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserId/tests/System/expected/test_ascSortOrder__UserId.getUsers_day.xml b/plugins/UserId/tests/System/expected/test_ascSortOrder__UserId.getUsers_day.xml
new file mode 100644
index 0000000000..9cf17c8b03
--- /dev/null
+++ b/plugins/UserId/tests/System/expected/test_ascSortOrder__UserId.getUsers_day.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>user3</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>1</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <idvisitor>0b7f849446d33835</idvisitor>
+ </row>
+ <row>
+ <label>user2</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>1</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <idvisitor>a1881c06eec96db9</idvisitor>
+ </row>
+ <row>
+ <label>user1</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_actions>3</nb_actions>
+ <nb_users>1</nb_users>
+ <max_actions>2</max_actions>
+ <sum_visit_length>1</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <idvisitor>b3daa77b4c04a955</idvisitor>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserId/tests/System/expected/test_ascSortOrder__UserId.getUsers_range.xml b/plugins/UserId/tests/System/expected/test_ascSortOrder__UserId.getUsers_range.xml
new file mode 100644
index 0000000000..99aa12454a
--- /dev/null
+++ b/plugins/UserId/tests/System/expected/test_ascSortOrder__UserId.getUsers_range.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>user1</label>
+ <nb_visits>11</nb_visits>
+ <nb_actions>15</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>7</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>10</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>10</sum_daily_nb_users>
+ <idvisitor>b3daa77b4c04a955</idvisitor>
+ </row>
+ <row>
+ <label>user2</label>
+ <nb_visits>21</nb_visits>
+ <nb_actions>29</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>8</sum_visit_length>
+ <bounce_count>13</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>20</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>20</sum_daily_nb_users>
+ <idvisitor>a1881c06eec96db9</idvisitor>
+ </row>
+ <row>
+ <label>user3</label>
+ <nb_visits>31</nb_visits>
+ <nb_actions>44</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>12</sum_visit_length>
+ <bounce_count>19</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>30</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>30</sum_daily_nb_users>
+ <idvisitor>0b7f849446d33835</idvisitor>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserId/tests/System/expected/test_limit__UserId.getUsers_day.xml b/plugins/UserId/tests/System/expected/test_limit__UserId.getUsers_day.xml
new file mode 100644
index 0000000000..52fcd98131
--- /dev/null
+++ b/plugins/UserId/tests/System/expected/test_limit__UserId.getUsers_day.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>user2</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>1</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <idvisitor>a1881c06eec96db9</idvisitor>
+ </row>
+ <row>
+ <label>user3</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>1</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <idvisitor>0b7f849446d33835</idvisitor>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserId/tests/System/expected/test_limit__UserId.getUsers_range.xml b/plugins/UserId/tests/System/expected/test_limit__UserId.getUsers_range.xml
new file mode 100644
index 0000000000..9545aadbb7
--- /dev/null
+++ b/plugins/UserId/tests/System/expected/test_limit__UserId.getUsers_range.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>user2</label>
+ <nb_visits>21</nb_visits>
+ <nb_actions>29</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>8</sum_visit_length>
+ <bounce_count>13</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>20</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>20</sum_daily_nb_users>
+ <idvisitor>a1881c06eec96db9</idvisitor>
+ </row>
+ <row>
+ <label>user1</label>
+ <nb_visits>11</nb_visits>
+ <nb_actions>15</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>7</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>10</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>10</sum_daily_nb_users>
+ <idvisitor>b3daa77b4c04a955</idvisitor>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserId/tests/System/expected/test_searchByUserId__UserId.getUsers_day.xml b/plugins/UserId/tests/System/expected/test_searchByUserId__UserId.getUsers_day.xml
new file mode 100644
index 0000000000..ac2a60152a
--- /dev/null
+++ b/plugins/UserId/tests/System/expected/test_searchByUserId__UserId.getUsers_day.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>user2</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>1</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <idvisitor>a1881c06eec96db9</idvisitor>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserId/tests/System/expected/test_searchByUserId__UserId.getUsers_range.xml b/plugins/UserId/tests/System/expected/test_searchByUserId__UserId.getUsers_range.xml
new file mode 100644
index 0000000000..ec3854dfb3
--- /dev/null
+++ b/plugins/UserId/tests/System/expected/test_searchByUserId__UserId.getUsers_range.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>user2</label>
+ <nb_visits>21</nb_visits>
+ <nb_actions>29</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>8</sum_visit_length>
+ <bounce_count>13</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>20</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>20</sum_daily_nb_users>
+ <idvisitor>a1881c06eec96db9</idvisitor>
+ </row>
+</result> \ No newline at end of file