~xibo-maintainers/xibo/tempel

« back to all changes in this revision

Viewing changes to lib/Widget/Twitter.php

  • Committer: GitHub
  • Author(s): Dan Garner
  • Date: 2016-11-16 11:51:16 UTC
  • Revision ID: git-v1:1cdd39222ff9fdd3fcc0bb8924cc706a24b18905
Bugfix/1.8.0 pack1 (#227)

* Library Tidy inaccessible
* Enabled notifications tidy task by default
* Implementation of "parent settings" so that TwitterMetro can use the API key/secret from Twitter.
* Fix for StatsArchive task infinite loop
* Fix for StatsArchive task processing ahead of now
* Flip clock to support countdown from a particular date, and daily countdown. xibosignage/xibo#936
* Fix date parsing when a timezone has been set
* Only save campaign if changes were made.
* Fix display notifications for removing dups
* XMR priv socket sleep to 100 ms
* Fix removal of Twig sources on release archive build. xibosignage/xibo#940
* Improve campaign layout assign/unassign xibosignage/xibo#941
* Tidy up unnecessary save in MediaInventory. Better logging for errors with sendfile from XMDS.
* Fix display status icon xibosignage/xibo#943
* Updated caching logic for required files
* Rewrite the nonce cache (required file) so that it uses a key per file instead of one storage object.
* Rework required files again - move back into the DB, but optimize nonce creation to ease contention.
* Further improvements to DB activity, basic connection management and stats reporting. Also deadlock protection statement.
* XMDS not updating bytes requested.
* More logging for retry deadlock loop
* Correct bandwidth logging. Fix deadlock loop.
* Improvements to media download (proper async). Fix for module downloads being copied rather than moved.
* Swagger doc fixes
* Convert XTR into a select and run single process script. Should fix it for windows.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
use Xibo\Exception\ConfigurationException;
28
28
use Xibo\Factory\ModuleFactory;
29
29
 
30
 
 
31
 
class Twitter extends ModuleWidget
 
30
/**
 
31
 * Class Twitter
 
32
 * @package Xibo\Widget
 
33
 */
 
34
class Twitter extends TwitterBase
32
35
{
33
36
    public $codeSchemaVersion = 1;
34
37
    private $resourceFolder;
221
224
        $this->setRawNode('javaScript', $this->getSanitizer()->getParam('javaScript', ''));
222
225
    }
223
226
 
224
 
    protected function getToken()
225
 
    {
226
 
        // Prepare the URL
227
 
        $url = 'https://api.twitter.com/oauth2/token';
228
 
 
229
 
        // Prepare the consumer key and secret
230
 
        $key = base64_encode(urlencode($this->getSetting('apiKey')) . ':' . urlencode($this->getSetting('apiSecret')));
231
 
 
232
 
        // Check to see if we have the bearer token already cached
233
 
        $cache = $this->getPool()->getItem('bearer_' . $key);
234
 
 
235
 
        $token = $cache->get();
236
 
 
237
 
        if ($cache->isHit()) {
238
 
            $this->getLog()->debug('Bearer Token served from cache');
239
 
            return $token;
240
 
        }
241
 
 
242
 
        $this->getLog()->debug('Bearer Token served from API');
243
 
 
244
 
        // Shame - we will need to get it.
245
 
        // and store it.
246
 
        $httpOptions = array(
247
 
            CURLOPT_TIMEOUT => 20,
248
 
            CURLOPT_SSL_VERIFYPEER => true,
249
 
            CURLOPT_HTTPHEADER => array(
250
 
                'POST /oauth2/token HTTP/1.1',
251
 
                'Authorization: Basic ' . $key,
252
 
                'Content-Type: application/x-www-form-urlencoded;charset=UTF-8',
253
 
                'Content-Length: 29'
254
 
            ),
255
 
            CURLOPT_USERAGENT => 'Xibo Twitter Module',
256
 
            CURLOPT_HEADER => false,
257
 
            CURLINFO_HEADER_OUT => true,
258
 
            CURLOPT_RETURNTRANSFER => true,
259
 
            CURLOPT_POST => true,
260
 
            CURLOPT_POSTFIELDS => http_build_query(array('grant_type' => 'client_credentials')),
261
 
            CURLOPT_URL => $url,
262
 
        );
263
 
 
264
 
        // Proxy support
265
 
        if ($this->getConfig()->GetSetting('PROXY_HOST') != '' && !$this->getConfig()->isProxyException($url)) {
266
 
            $httpOptions[CURLOPT_PROXY] = $this->getConfig()->GetSetting('PROXY_HOST');
267
 
            $httpOptions[CURLOPT_PROXYPORT] = $this->getConfig()->GetSetting('PROXY_PORT');
268
 
 
269
 
            if ($this->getConfig()->GetSetting('PROXY_AUTH') != '')
270
 
                $httpOptions[CURLOPT_PROXYUSERPWD] = $this->getConfig()->GetSetting('PROXY_AUTH');
271
 
        }
272
 
 
273
 
        $curl = curl_init();
274
 
 
275
 
        // Set options
276
 
        curl_setopt_array($curl, $httpOptions);
277
 
 
278
 
        // Call exec
279
 
        if (!$result = curl_exec($curl)) {
280
 
            // Log the error
281
 
            $this->getLog()->error('Error contacting Twitter API: ' . curl_error($curl));
282
 
            return false;
283
 
        }
284
 
 
285
 
        // We want to check for a 200
286
 
        $outHeaders = curl_getinfo($curl);
287
 
 
288
 
        if ($outHeaders['http_code'] != 200) {
289
 
            $this->getLog()->error('Twitter API returned ' . $result . ' status. Unable to proceed. Headers = ' . var_export($outHeaders, true));
290
 
 
291
 
            // See if we can parse the error.
292
 
            $body = json_decode($result);
293
 
 
294
 
            $this->getLog()->error('Twitter Error: ' . ((isset($body->errors[0])) ? $body->errors[0]->message : 'Unknown Error'));
295
 
 
296
 
            return false;
297
 
        }
298
 
 
299
 
        // See if we can parse the body as JSON.
300
 
        $body = json_decode($result);
301
 
 
302
 
        // We have a 200 - therefore we want to think about caching the bearer token
303
 
        // First, lets check its a bearer token
304
 
        if ($body->token_type != 'bearer') {
305
 
            $this->getLog()->error('Twitter API returned OK, but without a bearer token. ' . var_export($body, true));
306
 
            return false;
307
 
        }
308
 
 
309
 
        // It is, so lets cache it
310
 
        // long times...
311
 
        $cache->set($body->access_token);
312
 
        $cache->expiresAfter(100000);
313
 
        $this->getPool()->saveDeferred($cache);
314
 
 
315
 
        return $body->access_token;
316
 
    }
317
 
 
318
 
    protected function searchApi($token, $term, $resultType = 'mixed', $geoCode = '', $count = 15)
319
 
    {
320
 
        
321
 
        // Construct the URL to call
322
 
        $url = 'https://api.twitter.com/1.1/search/tweets.json';
323
 
        $queryString = '?q=' . urlencode(trim($term)) .
324
 
            '&result_type=' . $resultType .
325
 
            '&count=' . $count .
326
 
            '&include_entities=true' . 
327
 
            '&tweet_mode=extended';
328
 
 
329
 
        if ($geoCode != '')
330
 
            $queryString .= '&geocode=' . $geoCode;
331
 
 
332
 
        $httpOptions = array(
333
 
            CURLOPT_TIMEOUT => 20,
334
 
            CURLOPT_SSL_VERIFYPEER => true,
335
 
            CURLOPT_HTTPHEADER => array(
336
 
                'GET /1.1/search/tweets.json' . $queryString . 'HTTP/1.1',
337
 
                'Host: api.twitter.com',
338
 
                'Authorization: Bearer ' . $token
339
 
            ),
340
 
            CURLOPT_USERAGENT => 'Xibo Twitter Module',
341
 
            CURLOPT_HEADER => false,
342
 
            CURLINFO_HEADER_OUT => true,
343
 
            CURLOPT_RETURNTRANSFER => true,
344
 
            CURLOPT_URL => $url . $queryString,
345
 
        );
346
 
 
347
 
        // Proxy support
348
 
        if ($this->getConfig()->GetSetting('PROXY_HOST') != '' && !$this->getConfig()->isProxyException($url)) {
349
 
            $httpOptions[CURLOPT_PROXY] = $this->getConfig()->GetSetting('PROXY_HOST');
350
 
            $httpOptions[CURLOPT_PROXYPORT] = $this->getConfig()->GetSetting('PROXY_PORT');
351
 
 
352
 
            if ($this->getConfig()->GetSetting('PROXY_AUTH') != '')
353
 
                $httpOptions[CURLOPT_PROXYUSERPWD] = $this->getConfig()->GetSetting('PROXY_AUTH');
354
 
        }
355
 
 
356
 
        $this->getLog()->debug('Calling API with: ' . $url . $queryString);
357
 
 
358
 
        $curl = curl_init();
359
 
        curl_setopt_array($curl, $httpOptions);
360
 
        $result = curl_exec($curl);
361
 
 
362
 
        // Get the response headers
363
 
        $outHeaders = curl_getinfo($curl);
364
 
 
365
 
        if ($outHeaders['http_code'] == 0) {
366
 
            // Unable to connect
367
 
            $this->getLog()->error('Unable to reach twitter api.');
368
 
            return false;
369
 
        } else if ($outHeaders['http_code'] != 200) {
370
 
            $this->getLog()->error('Twitter API returned ' . $outHeaders['http_code'] . ' status. Unable to proceed. Headers = ' . var_export($outHeaders, true));
371
 
 
372
 
            // See if we can parse the error.
373
 
            $body = json_decode($result);
374
 
 
375
 
            $this->getLog()->error('Twitter Error: ' . ((isset($body->errors[0])) ? $body->errors[0]->message : 'Unknown Error'));
376
 
 
377
 
            return false;
378
 
        }
379
 
 
380
 
        // Parse out header and body
381
 
        $body = json_decode($result);
382
 
 
383
 
        return $body;
384
 
    }
385
 
 
 
227
    /**
 
228
     * @param int $displayId
 
229
     * @param bool $isPreview
 
230
     * @return array
 
231
     * @throws ConfigurationException
 
232
     */
386
233
    protected function getTwitterFeed($displayId = 0, $isPreview = true)
387
234
    {
388
235
        if (!extension_loaded('curl'))
501
348
        // Get the date format to apply
502
349
        $dateFormat = $this->getOption('dateFormat', $this->getConfig()->GetSetting('DATE_FORMAT'));
503
350
 
504
 
        // Store promises for file download
505
 
        $promises = [];
506
 
 
507
351
        // This should return the formatted items.
508
352
        foreach ($data->statuses as $tweet) {
509
353
            // Substitute for all matches in the template
587
431
                            $tweet->user->profile_image_url = str_replace('_normal', $imageSizeType, $tweet->user->profile_image_url);
588
432
                            
589
433
                            // Grab the profile image
590
 
                            $file = $this->mediaFactory->createModuleFile('twitter_' . $tweet->user->id, $tweet->user->profile_image_url);
591
 
                            $file->isRemote = true;
592
 
                            $file->expires = $expires;
593
 
                            $promises[] = $file->saveAsync();
 
434
                            $file = $this->mediaFactory->queueDownload('twitter_' . $tweet->user->id, $tweet->user->profile_image_url, $expires);
594
435
 
595
436
                            // Tag this layout with this file
596
437
                            $this->assignMedia($file->mediaId);
613
454
                            $photoUrl = $mediaObject->media_url;
614
455
                            
615
456
                            if ($photoUrl != '') {
616
 
                                $file = $this->mediaFactory->createModuleFile('twitter_photo_' . $tweet->user->id . '_' . $mediaObject->id_str, $photoUrl);
617
 
                                $file->isRemote = true;
618
 
                                $file->expires = $expires;
619
 
                                $promises[] = $file->saveAsync();
 
457
                                $file = $this->mediaFactory->queueDownload('twitter_photo_' . $tweet->user->id . '_' . $mediaObject->id_str, $photoUrl, $expires);
620
458
 
621
459
                                // Tag this layout with this file
622
460
                                $this->assignMedia($file->mediaId);
649
487
            $return[] = $rowString;
650
488
        }
651
489
 
652
 
        if (count($promises) > 0) {
653
 
            $this->getLog()->debug('There are ' . count($promises) . ' promises to resolve. Doing that now.');
654
 
            $promise = \GuzzleHttp\Promise\each_limit($promises, 5);
655
 
            $promise->wait();
656
 
        }
657
 
 
 
490
        // Process the download queue
 
491
        $this->mediaFactory->processDownloads();
658
492
 
659
493
        // Return the data array
660
494
        return $return;