~xibo-maintainers/xibo/tempel

« back to all changes in this revision

Viewing changes to lib/Controller/StatusDashboard.php

  • Committer: Dan Garner
  • Date: 2015-03-26 14:08:33 UTC
  • Revision ID: git-v1:70d14044444f8dc5d602b99890d59dea46d9470c
Moved web servable files to web folder

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 * along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
20
20
 */
21
21
namespace Xibo\Controller;
 
22
use Config;
22
23
use Exception;
23
 
use GuzzleHttp\Client;
24
 
use PicoFeed\PicoFeedException;
25
 
use PicoFeed\Reader\Reader;
26
 
use Stash\Interfaces\PoolInterface;
27
 
use Xibo\Factory\DisplayFactory;
28
 
use Xibo\Factory\DisplayGroupFactory;
29
 
use Xibo\Factory\MediaFactory;
30
 
use Xibo\Factory\UserFactory;
31
 
use Xibo\Helper\ByteFormatter;
32
 
use Xibo\Service\ConfigServiceInterface;
33
 
use Xibo\Service\DateServiceInterface;
34
 
use Xibo\Service\LogServiceInterface;
35
 
use Xibo\Service\SanitizerServiceInterface;
36
 
use Xibo\Storage\StorageServiceInterface;
 
24
use SimplePie;
 
25
use Xibo\Helper\Date;
 
26
use Xibo\Helper\Log;
 
27
use Xibo\Helper\Theme;
37
28
 
38
 
/**
39
 
 * Class StatusDashboard
40
 
 * @package Xibo\Controller
41
 
 */
42
29
class StatusDashboard extends Base
43
30
{
44
 
    /**
45
 
     * @var StorageServiceInterface
46
 
     */
47
 
    private $store;
48
 
 
49
 
    /**
50
 
     * @var PoolInterface
51
 
     */
52
 
    private $pool;
53
 
 
54
 
    /**
55
 
     * @var UserFactory
56
 
     */
57
 
    private $userFactory;
58
 
 
59
 
    /**
60
 
     * @var DisplayFactory
61
 
     */
62
 
    private $displayFactory;
63
 
 
64
 
    /**
65
 
     * @var DisplayGroupFactory
66
 
     */
67
 
    private $displayGroupFactory;
68
 
 
69
 
    /**
70
 
     * @var MediaFactory
71
 
     */
72
 
    private $mediaFactory;
73
 
 
74
 
    /**
75
 
     * Set common dependencies.
76
 
     * @param LogServiceInterface $log
77
 
     * @param SanitizerServiceInterface $sanitizerService
78
 
     * @param \Xibo\Helper\ApplicationState $state
79
 
     * @param \Xibo\Entity\User $user
80
 
     * @param \Xibo\Service\HelpServiceInterface $help
81
 
     * @param DateServiceInterface $date
82
 
     * @param ConfigServiceInterface $config
83
 
     * @param StorageServiceInterface $store
84
 
     * @param PoolInterface $pool
85
 
     * @param UserFactory $userFactory
86
 
     * @param DisplayFactory $displayFactory
87
 
     * @param DisplayGroupFactory $displayGroupFactory
88
 
     * @param MediaFactory $mediaFactory
89
 
     */
90
 
    public function __construct($log, $sanitizerService, $state, $user, $help, $date, $config, $store, $pool, $userFactory, $displayFactory, $displayGroupFactory, $mediaFactory)
91
 
    {
92
 
        $this->setCommonDependencies($log, $sanitizerService, $state, $user, $help, $date, $config);
93
 
 
94
 
        $this->store = $store;
95
 
        $this->pool = $pool;
96
 
        $this->userFactory = $userFactory;
97
 
        $this->displayFactory = $displayFactory;
98
 
        $this->displayGroupFactory = $displayGroupFactory;
99
 
        $this->mediaFactory = $mediaFactory;
100
 
    }
101
 
 
102
 
    /**
103
 
     * View
104
 
     */
105
31
    function displayPage()
106
32
    {
107
 
        $data = [];
108
 
 
109
33
        // Set up some suffixes
110
 
        $suffixes = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB');
 
34
        $suffixes = array('bytes', 'k', 'M', 'G', 'T');
111
35
 
 
36
        // Get some data for a bandwidth chart
112
37
        try {
113
 
            // Displays this user has access to
114
 
            $displays = $this->displayFactory->query(['display']);
115
 
            $displayIds = array_map(function($element) {
116
 
                return $element->displayId;
117
 
            }, $displays);
118
 
            $displayIds[] = -1;
119
 
 
120
 
            // Get some data for a bandwidth chart
121
 
            $dbh = $this->store->getConnection();
122
 
 
123
 
            $sql = '
124
 
              SELECT MAX(FROM_UNIXTIME(month)) AS month,
125
 
                  IFNULL(SUM(Size), 0) AS size
126
 
                FROM `bandwidth`
127
 
               WHERE month > :month AND displayId IN (' . implode(',', $displayIds) . ')
128
 
              GROUP BY MONTH(FROM_UNIXTIME(month)) ORDER BY MIN(month);
129
 
              ';
130
 
            $params = array('month' => time() - (86400 * 365));
131
 
 
132
 
 
133
 
            $results = $this->store->select($sql, $params);
 
38
            $dbh = \Xibo\Storage\PDOConnect::init();
 
39
 
 
40
            $sth = $dbh->prepare('SELECT FROM_UNIXTIME(month) AS month, IFNULL(SUM(Size), 0) AS size FROM `bandwidth` WHERE month > :month GROUP BY FROM_UNIXTIME(month) ORDER BY MIN(month);');
 
41
            $sth->execute(array('month' => time() - (86400 * 365)));
 
42
 
 
43
            $results = $sth->fetchAll();
134
44
 
135
45
            // Monthly bandwidth - optionally tested against limits
136
 
            $xmdsLimit = $this->getConfig()->GetSetting('MONTHLY_XMDS_TRANSFER_LIMIT_KB');
 
46
            $xmdsLimit = Config::GetSetting('MONTHLY_XMDS_TRANSFER_LIMIT_KB');
137
47
 
138
48
            $maxSize = 0;
139
49
            foreach ($results as $row) {
146
56
            if ($xmdsLimit > 0) {
147
57
                // Convert to appropriate size (xmds limit is in KB)
148
58
                $xmdsLimit = ($xmdsLimit * 1024) / (pow(1024, $base));
149
 
                $data['xmdsLimit'] = round($xmdsLimit, 2) . ' ' . $suffixes[$base];
 
59
                Theme::Set('xmdsLimit', $xmdsLimit . ' ' . $suffixes[$base]);
150
60
            }
151
61
 
152
 
            $labels = [];
153
 
            $usage = [];
154
 
            $limit = [];
 
62
            $output = array();
155
63
 
156
64
            foreach ($results as $row) {
157
 
                $labels[] = $this->getDate()->getLocalDate($this->getSanitizer()->getDate('month', $row), 'F');
158
 
 
159
65
                $size = ((double)$row['size']) / (pow(1024, $base));
160
 
                $usage[] = round($size, 2);
161
 
 
162
 
                $limit[] = round($xmdsLimit - $size, 2);
 
66
                $remaining = $xmdsLimit - $size;
 
67
                $output[] = array(
 
68
                    'label' => Date::getLocalDate(Date::getDateFromGregorianString($row['month']), 'F'),
 
69
                    'value' => round($size, 2),
 
70
                    'limit' => round($remaining, 2)
 
71
                );
163
72
            }
164
73
 
165
74
            // What if we are empty?
166
 
            if (count($results) == 0) {
167
 
                $labels[] = $this->getDate()->getLocalDate(null, 'F');
168
 
                $usage[] = 0;
169
 
                $limit[] = 0;
170
 
            }
171
 
 
172
 
            // Organise our datasets
173
 
            $dataSets = [
174
 
                [
175
 
                    'label' => __('Used'),
176
 
                    'backgroundColor' => ($xmdsLimit > 0) ? 'rgb(255, 0, 0)' : 'rgb(11, 98, 164)',
177
 
                    'data' => $usage
178
 
                ]
179
 
            ];
180
 
 
181
 
            if ($xmdsLimit > 0) {
182
 
                $dataSets[] = [
183
 
                    'label' => __('Available'),
184
 
                    'backgroundColor' => 'rgb(0, 204, 0)',
185
 
                    'data' => $limit
186
 
                ];
 
75
            if (count($output) == 0) {
 
76
                $output[] = array(
 
77
                    'label' => Date::getLocalDate(null, 'F'),
 
78
                    'value' => 0,
 
79
                    'limit' => 0
 
80
                );
187
81
            }
188
82
 
189
83
            // Set the data
190
 
            $data['xmdsLimitSet'] = ($xmdsLimit > 0);
191
 
            $data['bandwidthSuffix'] = $suffixes[$base];
192
 
            $data['bandwidthWidget'] = json_encode([
193
 
                'labels' => $labels,
194
 
                'datasets' => $dataSets
195
 
            ]);
 
84
            Theme::Set('xmdsLimitSet', ($xmdsLimit > 0));
 
85
            Theme::Set('bandwidthSuffix', $suffixes[$base]);
 
86
            Theme::Set('bandwidthWidget', json_encode($output));
196
87
 
197
88
            // We would also like a library usage pie chart!
198
 
            if ($this->getUser()->libraryQuota != 0) {
199
 
                $libraryLimit = $this->getUser()->libraryQuota * 1024;
200
 
            }
201
 
            else {
202
 
                $libraryLimit = $this->getConfig()->GetSetting('LIBRARY_SIZE_LIMIT_KB') * 1024;
203
 
            }
 
89
            $libraryLimit = Config::GetSetting('LIBRARY_SIZE_LIMIT_KB');
 
90
            $libraryLimit = $libraryLimit * 1024;
204
91
 
205
92
            // Library Size in Bytes
206
 
            $params = [];
207
 
            $sql = 'SELECT IFNULL(SUM(FileSize), 0) AS SumSize, type FROM `media` WHERE 1 = 1 ';
208
 
            $this->mediaFactory->viewPermissionSql('Xibo\Entity\Media', $sql, $params, '`media`.mediaId', '`media`.userId');
209
 
            $sql .= ' GROUP BY type ';
210
 
 
211
 
            $sth = $dbh->prepare($sql);
212
 
            $sth->execute($params);
 
93
            $sth = $dbh->prepare('SELECT IFNULL(SUM(FileSize), 0) AS SumSize, type FROM media GROUP BY type;');
 
94
            $sth->execute();
213
95
 
214
96
            $results = $sth->fetchAll();
215
97
 
227
109
            // Decide what our units are going to be, based on the size
228
110
            $base = ($maxSize == 0) ? 0 : floor(log($maxSize) / log(1024));
229
111
 
230
 
            $libraryUsage = [];
231
 
            $libraryLabels = [];
 
112
            $output = array();
232
113
            $totalSize = 0;
233
114
            foreach ($results as $library) {
234
 
                $libraryUsage[] = round((double)$library['SumSize'] / (pow(1024, $base)), 2);
235
 
                $libraryLabels[] = ucfirst($library['type']) . ' ' . $suffixes[$base];
236
 
 
 
115
                $output[] = array(
 
116
                    'value' => round((double)$library['SumSize'] / (pow(1024, $base)), 2),
 
117
                    'label' => ucfirst($library['type'])
 
118
                );
237
119
                $totalSize = $totalSize + $library['SumSize'];
238
120
            }
239
121
 
240
122
            // Do we need to add the library remaining?
241
123
            if ($libraryLimit > 0) {
242
124
                $remaining = round(($libraryLimit - $totalSize) / (pow(1024, $base)), 2);
243
 
 
244
 
                $libraryUsage[] = $remaining;
245
 
                $libraryLabels[] = __('Free') . ' ' . $suffixes[$base];
 
125
                $output[] = array(
 
126
                    'value' => $remaining,
 
127
                    'label' => __('Free')
 
128
                );
246
129
            }
247
130
 
248
131
            // What if we are empty?
249
 
            if (count($results) == 0 && $libraryLimit <= 0) {
250
 
                $libraryUsage[] = 0;
251
 
                $libraryLabels[] = __('Empty');
 
132
            if (count($output) == 0) {
 
133
                $output[] = array(
 
134
                    'label' => __('Empty'),
 
135
                    'value' => 0
 
136
                );
252
137
            }
253
138
 
254
 
            $data['libraryLimitSet'] = ($libraryLimit > 0);
255
 
            $data['libraryLimit'] = (round((double)$libraryLimit / (pow(1024, $base)), 2)) . ' ' . $suffixes[$base];
256
 
            $data['librarySize'] = ByteFormatter::format($totalSize, 1);
257
 
            $data['librarySuffix'] = $suffixes[$base];
258
 
            $data['libraryWidgetLabels'] = json_encode($libraryLabels);
259
 
            $data['libraryWidgetData'] = json_encode($libraryUsage);
 
139
            Theme::Set('libraryLimitSet', $libraryLimit);
 
140
            Theme::Set('libraryLimit', (round((double)$libraryLimit / (pow(1024, $base)), 2)) . ' ' . $suffixes[$base]);
 
141
            Theme::Set('librarySize', \Kit::formatBytes($totalSize, 1));
 
142
            Theme::Set('librarySuffix', $suffixes[$base]);
 
143
            Theme::Set('libraryWidget', json_encode($output));
260
144
 
261
145
            // Also a display widget
262
 
            $data['displays'] = $displays;
 
146
            $sort_order = array('display');
 
147
            $displays = $this->getUser()->DisplayList($sort_order);
 
148
 
 
149
            $rows = array();
 
150
 
 
151
            if (is_array($displays) && count($displays) > 0) {
 
152
                // Output a table showing the displays
 
153
                foreach ($displays as $display) {
 
154
                    /* @var \Xibo\Entity\Display $display */
 
155
                    $row['mediainventorystatus'] = ($display->mediaInventoryStatus == 1) ? 'success' : (($display->mediaInventoryStatus == 2) ? 'danger' : 'warning');
 
156
                    $row['display'] = $display->display;
 
157
                    $row['loggedin'] = $display->loggedIn;
 
158
                    $row['licensed'] = $display->licensed;
 
159
                    // Assign this to the table row
 
160
                    $rows[] = $row;
 
161
                }
 
162
            }
 
163
 
 
164
            Theme::Set('display-widget-rows', $rows);
263
165
 
264
166
            // Get a count of users
265
 
            $data['countUsers'] = count($this->userFactory->query());
266
 
 
267
 
            // Get a count of active layouts, only for display groups we have permission for
268
 
            $displayGroups = $this->displayGroupFactory->query(null, ['isDisplaySpecific' => -1]);
269
 
            $displayGroupIds = array_map(function($element) {
270
 
                return $element->displayGroupId;
271
 
            }, $displayGroups);
272
 
            // Add an empty one
273
 
            $displayGroupIds[] = -1;
274
 
 
275
 
            $sql = '
276
 
              SELECT IFNULL(COUNT(*), 0) AS count_scheduled 
277
 
                FROM `schedule` 
278
 
               WHERE (
279
 
                  :now BETWEEN FromDT AND ToDT
280
 
                  OR `schedule`.recurrence_range >= :now 
281
 
                  OR (
282
 
                    IFNULL(`schedule`.recurrence_range, 0) = 0 AND IFNULL(`schedule`.recurrence_type, \'\') <> \'\' 
283
 
                  )
284
 
                )
285
 
                AND eventId IN (
286
 
                  SELECT eventId 
287
 
                    FROM `lkscheduledisplaygroup` 
288
 
                   WHERE displayGroupId IN (' . implode(',', $displayGroupIds) . ')
289
 
                )
290
 
            ';
291
 
            $params = array('now' => time());
292
 
 
293
 
            $sth = $dbh->prepare($sql);
294
 
            $sth->execute($params);
295
 
 
296
 
            $data['nowShowing'] = $sth->fetchColumn(0);
 
167
            $sth = $dbh->prepare('SELECT IFNULL(COUNT(*), 0) AS count_users FROM `user`');
 
168
            $sth->execute();
 
169
 
 
170
            Theme::Set('countUsers', $sth->fetchColumn(0));
 
171
 
 
172
            // Get a count of active layouts
 
173
            $sth = $dbh->prepare('SELECT IFNULL(COUNT(*), 0) AS count_scheduled FROM `schedule_detail` WHERE :now BETWEEN FromDT AND ToDT');
 
174
            $sth->execute(array('now' => time()));
 
175
 
 
176
            Theme::Set('nowShowing', $sth->fetchColumn(0));
297
177
 
298
178
            // Latest news
299
 
            if ($this->getConfig()->GetSetting('DASHBOARD_LATEST_NEWS_ENABLED') == 1 && !empty($this->getConfig()->GetSetting('LATEST_NEWS_URL'))) {
 
179
            if (Config::GetSetting('DASHBOARD_LATEST_NEWS_ENABLED') == 1) {
300
180
                // Make sure we have the cache location configured
301
 
                Library::ensureLibraryExists($this->getConfig()->GetSetting('LIBRARY_LOCATION'));
302
 
 
303
 
                try {
304
 
                    $feedUrl = $this->getConfig()->GetSetting('LATEST_NEWS_URL');
305
 
                    $cache = $this->pool->getItem('rss/' . md5($feedUrl));
306
 
 
307
 
                    $latestNews = $cache->get();
308
 
 
309
 
                    // Check the cache
310
 
                    if ($cache->isMiss()) {
311
 
 
312
 
                        // Create a Guzzle Client to get the Feed XML
313
 
                        $client = new Client();
314
 
                        $response = $client->get($feedUrl, $this->getConfig()->getGuzzleProxy());
315
 
 
316
 
                        // Pull out the content type and body
317
 
                        $result = explode('charset=', $response->getHeaderLine('Content-Type'));
318
 
                        $document['encoding'] = isset($result[1]) ? $result[1] : '';
319
 
                        $document['xml'] = $response->getBody();
320
 
 
321
 
                        // Get the feed parser
322
 
                        $reader = new Reader();
323
 
                        $parser = $reader->getParser($feedUrl, $document['xml'], $document['encoding']);
324
 
 
325
 
                        // Get a feed object
326
 
                        $feed = $parser->execute();
327
 
 
328
 
                        // Parse the items in the feed
329
 
                        $latestNews = [];
330
 
 
331
 
                        foreach ($feed->getItems() as $item) {
332
 
                            /* @var \PicoFeed\Parser\Item $item */
333
 
 
334
 
                            // Try to get the description tag
335
 
                            if (!$desc = $item->getTag('description')) {
336
 
                                // use content with tags stripped
337
 
                                $content = strip_tags($item->getContent());
338
 
                            } else {
339
 
                                // use description
340
 
                                $content = (isset($desc[0]) ? $desc[0] : strip_tags($item->getContent()));
341
 
                            }
342
 
 
343
 
                            $latestNews[] = array(
344
 
                                'title' => $item->getTitle(),
345
 
                                'description' => $content,
346
 
                                'link' => $item->getUrl()
347
 
                            );
348
 
                        }
349
 
 
350
 
                        // Store in the cache for 1 day
351
 
                        $cache->set($latestNews);
352
 
                        $cache->expiresAfter(86400);
353
 
 
354
 
                        $this->pool->saveDeferred($cache);
 
181
                File::EnsureLibraryExists();
 
182
 
 
183
                // Use SimplePie to get the feed
 
184
                include_once('3rdparty/simplepie/autoloader.php');
 
185
 
 
186
                $feed = new SimplePie();
 
187
                $feed->set_cache_location(File::GetLibraryCacheUri());
 
188
                $feed->set_feed_url(Theme::GetConfig('latest_news_url'));
 
189
                $feed->set_cache_duration(86400);
 
190
                $feed->handle_content_type();
 
191
                $feed->init();
 
192
 
 
193
                $latestNews = array();
 
194
 
 
195
                if ($feed->error()) {
 
196
                    Log::notice('Feed Error: ' . $feed->error(), get_class(), __FUNCTION__);
 
197
                } else {
 
198
                    // Store our formatted items
 
199
                    foreach ($feed->get_items() as $item) {
 
200
                        $latestNews[] = array(
 
201
                            'title' => $item->get_title(),
 
202
                            'description' => $item->get_description(),
 
203
                            'link' => $item->get_link()
 
204
                        );
355
205
                    }
356
 
 
357
 
                    $data['latestNews'] = $latestNews;
358
 
                }
359
 
                catch (PicoFeedException $e) {
360
 
                    $this->getLog()->error('Unable to get feed: %s', $e->getMessage());
361
 
                    $this->getLog()->debug($e->getTraceAsString());
362
 
 
363
 
                    $data['latestNews'] = array(array('title' => __('Latest news not available.'), 'description' => '', 'link' => ''));
364
 
                }
 
206
                }
 
207
 
 
208
                Theme::Set('latestNews', $latestNews);
365
209
            }
366
210
            else {
367
 
                $data['latestNews'] = array(array('title' => __('Latest news not enabled.'), 'description' => '', 'link' => ''));
 
211
                Theme::Set('latestNews', array(array('title' => __('Latest news not enabled.'), 'description' => '', 'link' => '')));
368
212
            }
369
213
        }
370
214
        catch (Exception $e) {
371
215
 
372
 
            $this->getLog()->error($e->getMessage());
373
 
            $this->getLog()->debug($e->getTraceAsString());
 
216
            Log::error($e->getMessage());
374
217
 
375
218
            // Show the error in place of the bandwidth chart
376
 
            $data['widget-error'] = 'Unable to get widget details';
 
219
            Theme::Set('widget-error', 'Unable to get widget details');
377
220
        }
378
221
 
379
222
        // Do we have an embedded widget?
380
 
        $data['embeddedWidget'] = html_entity_decode($this->getConfig()->GetSetting('EMBEDDED_STATUS_WIDGET'));
 
223
        Theme::Set('embedded-widget', html_entity_decode(Config::GetSetting('EMBEDDED_STATUS_WIDGET')));
381
224
 
382
225
        // Render the Theme and output
383
 
        $this->getState()->template = 'dashboard-status-page';
384
 
        $this->getState()->setData($data);
 
226
        $this->getState()->html .= Theme::RenderReturn('status_dashboard');
385
227
    }
386
228
}