Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 402] [Versions 310 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * This plugin is used to access flickr pictures
  19   *
  20   * @since Moodle 2.0
  21   * @package    repository_flickr
  22   * @copyright  2010 Dongsheng Cai {@link http://dongsheng.org}
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  require_once($CFG->dirroot . '/repository/lib.php');
  26  require_once($CFG->libdir.'/flickrclient.php');
  27  
  28  /**
  29   * This plugin is used to access user's private flickr repository
  30   *
  31   * @since Moodle 2.0
  32   * @package    repository_flickr
  33   * @copyright  2009 Dongsheng Cai {@link http://dongsheng.org}
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   */
  36  class repository_flickr extends repository {
  37  
  38      /** @var flickr_client */
  39      protected $flickr;
  40  
  41      /** @var string oauth consumer key */
  42      protected $api_key;
  43  
  44      /** @var string oauth consumer secret */
  45      protected $secret;
  46  
  47      /** @var string oauth access token */
  48      protected $accesstoken;
  49  
  50      /** @var string oauth access token secret */
  51      protected $accesstokensecret;
  52  
  53      public $photos;
  54  
  55      /**
  56       * Stores sizes of images to prevent multiple API call
  57       */
  58      static private $sizes = array();
  59  
  60      /**
  61       *
  62       * @param int $repositoryid
  63       * @param object $context
  64       * @param array $options
  65       */
  66      public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
  67          global $SESSION, $CFG;
  68          $options['page']    = optional_param('p', 1, PARAM_INT);
  69          parent::__construct($repositoryid, $context, $options);
  70  
  71          $this->api_key = $this->get_option('api_key');
  72          $this->secret  = $this->get_option('secret');
  73  
  74          $this->accesstoken = get_user_preferences('repository_flickr_access_token');
  75          $this->accesstokensecret = get_user_preferences('repository_flickr_access_token_secret');
  76  
  77          $callbackurl = new moodle_url('/repository/repository_callback.php', ['repo_id' => $repositoryid]);
  78          $this->flickr = new flickr_client($this->api_key, $this->secret, $callbackurl);
  79          $this->flickr->set_access_token($this->accesstoken, $this->accesstokensecret);
  80      }
  81  
  82      /**
  83       * Check if the user has authorized us to make requests to Flickr API.
  84       *
  85       * @return bool
  86       */
  87      public function check_login() {
  88  
  89          if (empty($this->accesstoken) || empty($this->accesstokensecret)) {
  90              return false;
  91  
  92          } else {
  93              return true;
  94          }
  95      }
  96  
  97      /**
  98       * Purge the stored access token and related user data.
  99       *
 100       * @return string
 101       */
 102      public function logout() {
 103  
 104          set_user_preference('repository_flickr_access_token', null);
 105          set_user_preference('repository_flickr_access_token_secret', null);
 106  
 107          $this->accesstoken = null;
 108          $this->accesstokensecret = null;
 109  
 110          return $this->print_login();
 111      }
 112  
 113      /**
 114       *
 115       * @param array $options
 116       * @return mixed
 117       */
 118      public function set_option($options = array()) {
 119          if (!empty($options['api_key'])) {
 120              set_config('api_key', trim($options['api_key']), 'flickr');
 121          }
 122          if (!empty($options['secret'])) {
 123              set_config('secret', trim($options['secret']), 'flickr');
 124          }
 125          unset($options['api_key']);
 126          unset($options['secret']);
 127          $ret = parent::set_option($options);
 128          return $ret;
 129      }
 130  
 131      /**
 132       *
 133       * @param string $config
 134       * @return mixed
 135       */
 136      public function get_option($config = '') {
 137          if ($config==='api_key') {
 138              return trim(get_config('flickr', 'api_key'));
 139          } elseif ($config ==='secret') {
 140              return trim(get_config('flickr', 'secret'));
 141          } else {
 142              $options['api_key'] = trim(get_config('flickr', 'api_key'));
 143              $options['secret']  = trim(get_config('flickr', 'secret'));
 144          }
 145          $options = parent::get_option($config);
 146          return $options;
 147      }
 148  
 149      /**
 150       *
 151       * @return bool
 152       */
 153      public function global_search() {
 154          if (empty($this->token)) {
 155              return false;
 156          } else {
 157              return true;
 158          }
 159      }
 160  
 161      /**
 162       * Show the interface to log in to Flickr..
 163       *
 164       * @return string|array
 165       */
 166      public function print_login() {
 167  
 168          $reqtoken = $this->flickr->request_token();
 169          $this->flickr->set_request_token_secret(['caller' => 'repository_flickr'], $reqtoken['oauth_token_secret']);
 170  
 171          // Even when the Flick auth docs states the "perms" argument is
 172          // optional, it does not work without it.
 173          $authurl = new moodle_url($reqtoken['authorize_url'], array('perms' => 'read'));
 174  
 175          if ($this->options['ajax']) {
 176              return [
 177                  'login' => [
 178                      [
 179                          'type' => 'popup',
 180                          'url' => $authurl->out(false),
 181                      ],
 182                  ],
 183              ];
 184  
 185          } else {
 186              echo '<a target="_blank" href="'.$authurl->out().'">'.get_string('login', 'repository').'</a>';
 187          }
 188      }
 189  
 190      /**
 191       * Search for the user's photos at Flickr
 192       *
 193       * @param string $searchtext Photos with title, description or tags containing the text will be returned
 194       * @param int $page Page number to load
 195       * @return array
 196       */
 197      public function search($searchtext, $page = 0) {
 198  
 199          $response = $this->flickr->call('photos.search', [
 200              'user_id' => 'me',
 201              'per_page' => 24,
 202              'extras' => 'original_format,url_sq,url_o,date_upload,last_update,owner_name,license',
 203              'page' => $page,
 204              'text' => $searchtext,
 205          ]);
 206  
 207          if ($response === false) {
 208              $this->logout();
 209              return [];
 210          }
 211  
 212          // Convert the response to the format expected by the filepicker.
 213          $ret = [
 214              'manage' => 'https://www.flickr.com/photos/organize',
 215              'list' => [],
 216              'pages' => $response->photos->pages,
 217              'total' => $response->photos->total,
 218              'perpage' => $response->photos->perpage,
 219              'page' => $response->photos->page,
 220          ];
 221  
 222          if (!empty($response->photos->photo)) {
 223              foreach ($response->photos->photo as $p) {
 224                  if (empty($p->title)) {
 225                      $p->title = get_string('notitle', 'repository_flickr');
 226                  }
 227  
 228                  if (isset($p->originalformat)) {
 229                      $format = $p->originalformat;
 230                  } else {
 231                      $format = 'jpg';
 232                  }
 233                  $format = '.'.$format;
 234  
 235                  // Append extension to the file name.
 236                  if (substr($p->title, strlen($p->title) - strlen($format)) != $format) {
 237                      $p->title .= $format;
 238                  }
 239  
 240                  // Perform a HEAD request to the image to obtain it's Content-Length.
 241                  $curl = new curl();
 242                  $curl->head($p->url_o);
 243  
 244                  $ret['list'][] = [
 245                      'title' => $p->title,
 246                      'source' => $p->id,
 247                      'id' => $p->id,
 248                      'thumbnail' => $p->url_sq,
 249                      'datecreated' => $p->dateupload,
 250                      'datemodified' => $p->lastupdate,
 251                      'url' => $p->url_o,
 252                      'author' => $p->ownername,
 253                      'size' => (int)($curl->get_info()['download_content_length']),
 254                      'image_width' => $p->width_o,
 255                      'image_height' => $p->height_o,
 256                      'license' => $this->license4moodle((int) $p->license),
 257                  ];
 258              }
 259          }
 260  
 261          // Filter file listing to display specific types only.
 262          $ret['list'] = array_filter($ret['list'], array($this, 'filter'));
 263  
 264          return $ret;
 265      }
 266  
 267      /**
 268       * Map Flickr license ID to those used internally by Moodle
 269       *
 270       * @param int $licenseid
 271       * @return string
 272       */
 273      public function license4moodle(int $licenseid): string {
 274          $license = [
 275              0 => 'allrightsreserved',
 276              1 => 'cc-nc-sa',
 277              2 => 'cc-nc',
 278              3 => 'cc-nc-nd',
 279              4 => 'cc',
 280              5 => 'cc-sa',
 281              6 => 'cc-nd',
 282              7 => 'other'
 283          ];
 284          return $license[$licenseid];
 285      }
 286  
 287      /**
 288       *
 289       * @param string $path
 290       * @param int $page
 291       * @return array
 292       */
 293      public function get_listing($path = '', $page = '') {
 294          return $this->search('', $page);
 295      }
 296  
 297      public function get_link($photoid) {
 298          return $this->flickr->get_photo_url($photoid);
 299      }
 300  
 301      /**
 302       *
 303       * @param string $photoid
 304       * @param string $file
 305       * @return string
 306       */
 307      public function get_file($photoid, $file = '') {
 308          return parent::get_file($this->flickr->get_photo_url($photoid), $file);
 309      }
 310  
 311      /**
 312       * Add Plugin settings input to Moodle form
 313       * @param object $mform
 314       */
 315      public static function type_config_form($mform, $classname = 'repository') {
 316          global $CFG;
 317          $api_key = get_config('flickr', 'api_key');
 318          $secret = get_config('flickr', 'secret');
 319  
 320          if (empty($api_key)) {
 321              $api_key = '';
 322          }
 323          if (empty($secret)) {
 324              $secret = '';
 325          }
 326  
 327          parent::type_config_form($mform);
 328  
 329          $strrequired = get_string('required');
 330          $mform->addElement('text', 'api_key', get_string('apikey', 'repository_flickr'), array('value'=>$api_key,'size' => '40'));
 331          $mform->setType('api_key', PARAM_RAW_TRIMMED);
 332          $mform->addElement('text', 'secret', get_string('secret', 'repository_flickr'), array('value'=>$secret,'size' => '40'));
 333          $mform->setType('secret', PARAM_RAW_TRIMMED);
 334  
 335          //retrieve the flickr instances
 336          $params = array();
 337          $params['context'] = array();
 338          //$params['currentcontext'] = $this->context;
 339          $params['onlyvisible'] = false;
 340          $params['type'] = 'flickr';
 341          $instances = repository::get_instances($params);
 342          if (empty($instances)) {
 343              $callbackurl = get_string('callbackwarning', 'repository_flickr');
 344              $mform->addElement('static', null, '',  $callbackurl);
 345          } else {
 346              $instance = array_shift($instances);
 347              $callbackurl = $CFG->wwwroot.'/repository/repository_callback.php?repo_id='.$instance->id;
 348              $mform->addElement('static', 'callbackurl', '', get_string('callbackurltext', 'repository_flickr', $callbackurl));
 349          }
 350  
 351          $mform->addRule('api_key', $strrequired, 'required', null, 'client');
 352          $mform->addRule('secret', $strrequired, 'required', null, 'client');
 353      }
 354  
 355      /**
 356       * Names of the plugin settings
 357       * @return array
 358       */
 359      public static function get_type_option_names() {
 360          return array('api_key', 'secret', 'pluginname');
 361      }
 362      public function supported_filetypes() {
 363          return array('web_image');
 364      }
 365      public function supported_returntypes() {
 366          return (FILE_INTERNAL | FILE_EXTERNAL);
 367      }
 368  
 369      /**
 370       * Return the source information
 371       *
 372       * @param string $photoid
 373       * @return string|null
 374       */
 375      public function get_file_source_info($photoid) {
 376          return $this->flickr->get_photo_url($photoid);
 377      }
 378  
 379      /**
 380       * Handle the oauth authorize callback
 381       *
 382       * This is to exchange the approved request token for an access token.
 383       */
 384      public function callback() {
 385  
 386          $token = required_param('oauth_token', PARAM_RAW);
 387          $verifier = required_param('oauth_verifier', PARAM_RAW);
 388          $secret = $this->flickr->get_request_token_secret(['caller' => 'repository_flickr']);
 389  
 390          // Exchange the request token for the access token.
 391          $accesstoken = $this->flickr->get_access_token($token, $secret, $verifier);
 392  
 393          // Store the access token and the access token secret in the user preferences.
 394          set_user_preference('repository_flickr_access_token', $accesstoken['oauth_token']);
 395          set_user_preference('repository_flickr_access_token_secret', $accesstoken['oauth_token_secret']);
 396      }
 397  }