diff --git a/repository/flickr/lib.php b/repository/flickr/lib.php index 8e16011d7d7..84d683ae90c 100644 --- a/repository/flickr/lib.php +++ b/repository/flickr/lib.php @@ -23,7 +23,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once($CFG->dirroot . '/repository/lib.php'); -require_once($CFG->libdir.'/flickrlib.php'); +require_once($CFG->libdir.'/flickrclient.php'); /** * This plugin is used to access user's private flickr repository @@ -34,7 +34,22 @@ require_once($CFG->libdir.'/flickrlib.php'); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class repository_flickr extends repository { - private $flickr; + + /** @var flickr_client */ + protected $flickr; + + /** @var string oauth consumer key */ + protected $api_key; + + /** @var string oauth consumer secret */ + protected $secret; + + /** @var string oauth access token */ + protected $accesstoken; + + /** @var string oauth access token secret */ + protected $accesstokensecret; + public $photos; /** @@ -53,44 +68,45 @@ class repository_flickr extends repository { $options['page'] = optional_param('p', 1, PARAM_INT); parent::__construct($repositoryid, $context, $options); - $this->setting = 'flickr_'; - $this->api_key = $this->get_option('api_key'); $this->secret = $this->get_option('secret'); - $this->token = get_user_preferences($this->setting, ''); - $this->nsid = get_user_preferences($this->setting.'_nsid', ''); - - $this->flickr = new phpFlickr($this->api_key, $this->secret, $this->token); - - $frob = optional_param('frob', '', PARAM_RAW); - if (empty($this->token) && !empty($frob)) { - $auth_info = $this->flickr->auth_getToken($frob); - $this->token = $auth_info['token']; - $this->nsid = $auth_info['user']['nsid']; - set_user_preference($this->setting, $auth_info['token']); - set_user_preference($this->setting.'_nsid', $auth_info['user']['nsid']); - } + $this->accesstoken = get_user_preferences('repository_flickr_access_token'); + $this->accesstokensecret = get_user_preferences('repository_flickr_access_token_secret'); + $callbackurl = new moodle_url('/repository/repository_callback.php', ['repo_id' => $repositoryid]); + $this->flickr = new flickr_client($this->api_key, $this->secret, $callbackurl); + $this->flickr->set_access_token($this->accesstoken, $this->accesstokensecret); } /** + * Check if the user has authorized us to make requests to Flickr API. * * @return bool */ public function check_login() { - return !empty($this->token); + + if (empty($this->accesstoken) || empty($this->accesstokensecret)) { + return false; + + } else { + return true; + } } /** + * Purge the stored access token and related user data. * - * @return mixed + * @return string */ public function logout() { - set_user_preference($this->setting, ''); - set_user_preference($this->setting.'_nsid', ''); - $this->token = ''; - $this->nsid = ''; + + set_user_preference('repository_flickr_access_token', null); + set_user_preference('repository_flickr_access_token_secret', null); + + $this->accesstoken = null; + $this->accesstokensecret = null; + return $this->print_login(); } @@ -143,77 +159,104 @@ class repository_flickr extends repository { } /** + * Show the interface to log in to Flickr.. * - * @return null + * @return string|array */ public function print_login() { + + $reqtoken = $this->flickr->request_token(); + $this->flickr->set_request_token_secret(['caller' => 'repository_flickr'], $reqtoken['oauth_token_secret']); + + // Even when the Flick auth docs states the "perms" argument is + // optional, it does not work without it. + $authurl = new moodle_url($reqtoken['authorize_url'], array('perms' => 'read')); + if ($this->options['ajax']) { - $ret = array(); - $popup_btn = new stdClass(); - $popup_btn->type = 'popup'; - $popup_btn->url = $this->flickr->auth(); - $ret['login'] = array($popup_btn); - return $ret; + return [ + 'login' => [ + [ + 'type' => 'popup', + 'url' => $authurl->out(false), + ], + ], + ]; + } else { - echo ''.get_string('login', 'repository').''; + echo ''.get_string('login', 'repository').''; } } /** - * Converts result received from phpFlickr::photo_search to Filepicker/repository format + * Search for the user's photos at Flickr * - * @param mixed $photos + * @param string $searchtext Photos with title, description or tags containing the text will be returned + * @param int $page Page number to load * @return array */ - private function build_list($photos) { - $photos_url = $this->flickr->urls_getUserPhotos($this->nsid); - $ret = array(); - $ret['manage'] = $photos_url; - $ret['list'] = array(); - $ret['pages'] = $photos['pages']; - $ret['total'] = $photos['total']; - $ret['perpage'] = $photos['perpage']; - $ret['page'] = $photos['page']; - if (!empty($photos['photo'])) { - foreach ($photos['photo'] as $p) { - if(empty($p['title'])) { - $p['title'] = get_string('notitle', 'repository_flickr'); + public function search($searchtext, $page = 0) { + + $response = $this->flickr->call('photos.search', [ + 'user_id' => 'me', + 'per_page' => 24, + 'extras' => 'original_format,url_sq,url_o,date_upload,owner_name', + 'page' => $page, + 'text' => $searchtext, + ]); + + if ($response === false) { + $this->logout(); + return []; + } + + // Convert the response to the format expected by the filepicker. + + $ret = [ + 'manage' => 'https://www.flickr.com/photos/organize', + 'list' => [], + 'pages' => $response->photos->pages, + 'total' => $response->photos->total, + 'perpage' => $response->photos->perpage, + 'page' => $response->photos->page, + ]; + + if (!empty($response->photos->photo)) { + foreach ($response->photos->photo as $p) { + if (empty($p->title)) { + $p->title = get_string('notitle', 'repository_flickr'); } - if (isset($p['originalformat'])) { - $format = $p['originalformat']; + + if (isset($p->originalformat)) { + $format = $p->originalformat; } else { $format = 'jpg'; } $format = '.'.$format; - // append extensions to the files - if (substr($p['title'], strlen($p['title'])-strlen($format)) != $format) { - $p['title'] .= $format; + + // Append extension to the file name. + if (substr($p->title, strlen($p->title) - strlen($format)) != $format) { + $p->title .= $format; } - $ret['list'][] = array('title'=>$p['title'],'source'=>$p['id'], - 'id'=>$p['id'],'thumbnail'=>$this->flickr->buildPhotoURL($p, 'Square'), - 'thumbnail_width'=>75, 'thumbnail_height'=>75, - 'date'=>'', 'size'=>'unknown', 'url'=>$photos_url.$p['id']); + + $ret['list'][] = [ + 'title' => $p->title, + 'source' => $p->id, + 'id' => $p->id, + 'thumbnail' => $p->url_sq, + 'thumbnail_width' => $p->width_sq, + 'thumbnail_height' => $p->height_sq, + 'date' => $p->dateupload, + 'url' => $p->url_o, + 'author' => $p->ownername, + 'size' => null, + 'license' => '', + ]; } } - return $ret; - } - /** - * - * @param string $search_text - * @param int $page - * @return array - */ - public function search($search_text, $page = 0) { - $photos = $this->flickr->photos_search(array( - 'user_id'=>$this->nsid, - 'per_page'=>24, - 'extras'=>'original_format', - 'page'=>$page, - 'text'=>$search_text - )); - $ret = $this->build_list($photos); - $ret['list'] = array_filter($ret['list'], array($this, 'filter')); // TODO this breaks pagination + // Filter file listing to display specific types only. + $ret['list'] = array_filter($ret['list'], array($this, 'filter')); + return $ret; } @@ -227,45 +270,8 @@ class repository_flickr extends repository { return $this->search('', $page); } - /** - * Return photo url by given photo id - * @param string $photoid - * @return string - */ - private function build_photo_url($photoid) { - $bestsize = $this->get_best_size($photoid); - if (!isset($bestsize['source'])) { - throw new repository_exception('cannotdownload', 'repository'); - } - return $bestsize['source']; - } - - /** - * Returns the best size for a photo - * - * @param string $photoid the photo identifier - * @return array of information provided by the API - */ - protected function get_best_size($photoid) { - if (!isset(self::$sizes[$photoid])) { - // Sizes are returned from smallest to greatest. - self::$sizes[$photoid] = $this->flickr->photos_getSizes($photoid); - } - $sizes = self::$sizes[$photoid]; - $bestsize = array(); - if (is_array($sizes)) { - while ($bestsize = array_pop($sizes)) { - // Make sure the source is set. Exit the loop if found. - if (isset($bestsize['source'])) { - break; - } - } - } - return $bestsize; - } - public function get_link($photoid) { - return $this->build_photo_url($photoid); + return $this->flickr->get_photo_url($photoid); } /** @@ -275,8 +281,7 @@ class repository_flickr extends repository { * @return string */ public function get_file($photoid, $file = '') { - $url = $this->build_photo_url($photoid); - return parent::get_file($url, $file); + return parent::get_file($this->flickr->get_photo_url($photoid), $file); } /** @@ -344,6 +349,25 @@ class repository_flickr extends repository { * @return string|null */ public function get_file_source_info($photoid) { - return $this->build_photo_url($photoid); + return $this->flickr->get_photo_url($photoid); + } + + /** + * Handle the oauth authorize callback + * + * This is to exchange the approved request token for an access token. + */ + public function callback() { + + $token = required_param('oauth_token', PARAM_RAW); + $verifier = required_param('oauth_verifier', PARAM_RAW); + $secret = $this->flickr->get_request_token_secret(['caller' => 'repository_flickr']); + + // Exchange the request token for the access token. + $accesstoken = $this->flickr->get_access_token($token, $secret, $verifier); + + // Store the access token and the access token secret in the user preferences. + set_user_preference('repository_flickr_access_token', $accesstoken['oauth_token']); + set_user_preference('repository_flickr_access_token_secret', $accesstoken['oauth_token_secret']); } }