1<?php
2/**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9namespace Piwik\Plugins\Live;
10
11use Piwik\API\Request;
12use Piwik\Common;
13use Piwik\Config;
14use Piwik\Piwik;
15use Piwik\DataTable;
16use Piwik\Plugins\Goals\API as APIGoals;
17use Piwik\Plugins\Live\Visualizations\VisitorLog;
18use Piwik\Url;
19use Piwik\View;
20
21/**
22 */
23class Controller extends \Piwik\Plugin\Controller
24{
25    const SIMPLE_VISIT_COUNT_WIDGET_LAST_MINUTES_CONFIG_KEY = 'live_widget_visitor_count_last_minutes';
26
27    private $profileSummaryProvider;
28
29    public function __construct(ProfileSummaryProvider $profileSummaryProvider)
30    {
31        $this->profileSummaryProvider = $profileSummaryProvider;
32        parent::__construct();
33    }
34
35    function index()
36    {
37        return $this->widget();
38    }
39
40    public function widget()
41    {
42        Piwik::checkUserHasViewAccess($this->idSite);
43        Live::checkIsVisitorLogEnabled($this->idSite);
44
45        $view = new View('@Live/index');
46        $view->idSite = $this->idSite;
47        $view->isWidgetized = Common::getRequestVar('widget', 0, 'int');
48        $view = $this->setCounters($view);
49        $view->liveRefreshAfterMs = (int)Config::getInstance()->General['live_widget_refresh_after_seconds'] * 1000;
50        $view->visitors = $this->getLastVisitsStart();
51        $view->liveTokenAuth = Piwik::getCurrentUserTokenAuth();
52        return $this->render($view);
53    }
54
55    public function ajaxTotalVisitors()
56    {
57        Piwik::checkUserHasViewAccess($this->idSite);
58
59        $view = new View('@Live/ajaxTotalVisitors');
60        $view = $this->setCounters($view);
61        $view->idSite = $this->idSite;
62        return $this->render($view);
63    }
64
65    private function render(View $view)
66    {
67        $rendered = $view->render();
68
69        return $rendered;
70    }
71
72    public function indexVisitorLog()
73    {
74        Piwik::checkUserHasViewAccess($this->idSite);
75        Live::checkIsVisitorLogEnabled($this->idSite);
76
77        $view = new View('@Live/indexVisitorLog.twig');
78        $view->visitorLog = $this->renderReport('getLastVisitsDetails');
79        return $view->render();
80    }
81
82    /**
83     * Widget
84     */
85    public function getVisitorLog()
86    {
87        return $this->renderReport('getLastVisitsDetails');
88    }
89
90    public function getLastVisitsStart()
91    {
92        Piwik::checkUserHasViewAccess($this->idSite);
93        Live::checkIsVisitorLogEnabled($this->idSite);
94
95        // hack, ensure we load today's visits by default
96        $_GET['date'] = 'today';
97        \Piwik\Period\Factory::checkPeriodIsEnabled('day');
98        $_GET['period'] = 'day';
99
100        $view = new View('@Live/getLastVisitsStart');
101        $view->idSite = (int) $this->idSite;
102        $error = '';
103        $visitors = new DataTable();
104        try {
105            $api = new Request("method=Live.getLastVisitsDetails&idSite={$this->idSite}&filter_limit=10&format=original&serialize=0&disable_generic_filters=1");
106            $visitors = $api->process();
107        } catch (\Exception $e) {
108            $error = $e->getMessage();
109        }
110        $view->error = $error;
111        $view->visitors = $visitors;
112
113        return $this->render($view);
114    }
115
116    private function setCounters($view)
117    {
118        $segment = Request::getRawSegmentFromRequest();
119        $last30min = Request::processRequest('Live.getCounters', [
120            'idSite' => $this->idSite,
121            'lastMinutes' => 30,
122            'segment' => $segment,
123            'showColumns' => 'visits,actions',
124        ], $default = []);
125        $last30min = $last30min[0];
126        $today = Request::processRequest('Live.getCounters', [
127            'idSite' => $this->idSite,
128            'lastMinutes' => 24 * 60,
129            'segment' => $segment,
130            'showColumns' => 'visits,actions',
131        ], $default = []);
132        $today = $today[0];
133        $view->visitorsCountHalfHour = $last30min['visits'];
134        $view->visitorsCountToday = $today['visits'];
135        $view->pisHalfhour = $last30min['actions'];
136        $view->pisToday = $today['actions'];
137        return $view;
138    }
139
140    /**
141     * Echo's HTML for visitor profile popup.
142     */
143    public function getVisitorProfilePopup()
144    {
145        Piwik::checkUserHasViewAccess($this->idSite);
146        Live::checkIsVisitorProfileEnabled($this->idSite);
147
148        $visitorData = Request::processRequest('Live.getVisitorProfile');
149
150        if (empty($visitorData)) {
151            throw new \Exception('Visitor could not be found'); // for example when URL parameter is not set
152        }
153
154        VisitorLog::groupActionsByPageviewId($visitorData['lastVisits']);
155
156        $view = new View('@Live/getVisitorProfilePopup.twig');
157        $view->idSite = $this->idSite;
158        $view->goals = Request::processRequest('Goals.getGoals', ['idSite' => $this->idSite, 'filter_limit' => '-1'], $default = []);
159        $view->visitorData = $visitorData;
160        $view->exportLink = $this->getVisitorProfileExportLink();
161
162        $this->setWidgetizedVisitorProfileUrl($view);
163
164        $summaryEntries = array();
165
166        $profileSummaries = $this->profileSummaryProvider->getAllInstances();
167        foreach ($profileSummaries as $profileSummary) {
168            $profileSummary->setProfile($view->visitorData);
169            $summaryEntries[] = [$profileSummary->getOrder(), $profileSummary->render()];
170        }
171
172        usort($summaryEntries, function($a, $b) {
173            return version_compare($a[0], $b[0]);
174        });
175
176        $summary = '';
177
178        foreach ($summaryEntries AS $summaryEntry) {
179            $summary .= $summaryEntry[1];
180        }
181
182        $view->profileSummary = $summary;
183
184        return $view->render();
185    }
186
187    public function getVisitList()
188    {
189        $this->checkSitePermission();
190        Piwik::checkUserHasViewAccess($this->idSite);
191
192        $filterLimit = Common::getRequestVar('filter_offset', 0, 'int');
193        $startCounter = Common::getRequestVar('start_number', 0, 'int');
194        $limit = Config::getInstance()->General['live_visitor_profile_max_visits_to_aggregate'];
195
196        if ($startCounter >= $limit) {
197            return ''; // do not return more visits than configured for profile
198        }
199
200        $nextVisits = Request::processRequest('Live.getLastVisitsDetails', array(
201                                                                                'segment'                 => Live::getSegmentWithVisitorId(),
202                                                                                'filter_limit'            => VisitorProfile::VISITOR_PROFILE_MAX_VISITS_TO_SHOW,
203                                                                                'filter_offset'           => $filterLimit,
204                                                                                'period'                  => false,
205                                                                                'date'                    => false
206                                                                           ));
207
208        if (empty($nextVisits)) {
209            return '';
210        }
211
212        VisitorLog::groupActionsByPageviewId($nextVisits);
213
214        $view = new View('@Live/getVisitList.twig');
215        $view->idSite = $this->idSite;
216        $view->startCounter = $startCounter < $nextVisits->getRowsCount() ? $nextVisits->getRowsCount() : $startCounter;
217        $view->visits = $nextVisits;
218        return $view->render();
219    }
220
221    private function getVisitorProfileExportLink()
222    {
223        return Url::getCurrentQueryStringWithParametersModified(array(
224                                                                     'module'   => 'API',
225                                                                     'action'   => 'index',
226                                                                     'method'   => 'Live.getVisitorProfile',
227                                                                     'format'   => 'XML',
228                                                                     'expanded' => 1
229                                                                ));
230    }
231
232    private function setWidgetizedVisitorProfileUrl($view)
233    {
234        if (\Piwik\Plugin\Manager::getInstance()->isPluginLoaded('Widgetize')) {
235            $view->widgetizedLink = Url::getCurrentQueryStringWithParametersModified(array(
236                                                                                          'module'            => 'Widgetize',
237                                                                                          'action'            => 'iframe',
238                                                                                          'moduleToWidgetize' => 'Live',
239                                                                                          'actionToWidgetize' => 'getVisitorProfilePopup'
240                                                                                     ));
241        }
242    }
243}
244