MDL-29857 - google apis: Convert to OAuth 2.0
authorDan Poltawski <dan@moodle.com>
Sun, 13 May 2012 16:42:24 +0000 (00:42 +0800)
committerDan Poltawski <dan@moodle.com>
Wed, 30 May 2012 16:00:25 +0000 (00:00 +0800)
Updated the various plugins to use OAuth 2.0 for authentication
against google apis. Google are phasing out AuthSub and pushing OAuth as
the replacement.

This changes repository_googledocs, repository_picasa,
portfolio_googledocs and portfolio_picasa

The token for requests is now stored in session rather than a user
prefence and it persists less but doesn't bother the user more than
necessary.

The google docs portfolio plugin is converted to use resumable upload
API as this appears to be what Google have replaced this with.

Unfortunately unlike authsub OAuth will require some setup by admins,
this is linked as a docs page.

15 files changed:
lib/googleapi.php
portfolio/googledocs/lang/en/portfolio_googledocs.php
portfolio/googledocs/lib.php
portfolio/googledocs/version.php
portfolio/picasa/lang/en/portfolio_picasa.php
portfolio/picasa/lib.php
portfolio/picasa/version.php
repository/googledocs/db/upgrade.php [moved from portfolio/picasa/db/events.php with 58% similarity]
repository/googledocs/lang/en/repository_googledocs.php
repository/googledocs/lib.php
repository/googledocs/version.php
repository/picasa/db/upgrade.php [moved from portfolio/googledocs/db/events.php with 58% similarity]
repository/picasa/lang/en/repository_picasa.php
repository/picasa/lib.php
repository/picasa/version.php

index 5129294..5994dd3 100644 (file)
 <?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
 /**
- * Moodle - Modular Object-Oriented Dynamic Learning Environment
- *          http://moodle.org
- * Copyright (C) 1999 onwards Martin Dougiamas  http://dougiamas.com
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * Simple implementation of some Google API functions for Moodle.
  *
- * @package    core
- * @subpackage lib
+ * @package   core
  * @copyright Dan Poltawski <talktodan@gmail.com>
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- *
- * Simple implementation of some Google API functions for Moodle.
  */
 
 defined('MOODLE_INTERNAL') || die();
 
- /** Include essential file */
 require_once($CFG->libdir.'/filelib.php');
+require_once($CFG->libdir.'/oauthlib.php');
 
 /**
- * Base class for google authenticated http requests
- *
- * Most Google API Calls required that requests are sent with an
- * Authorization header + token. This class extends the curl class
- * to aid this
- *
- * @package    moodlecore
- * @subpackage lib
- * @copyright Dan Poltawski <talktodan@gmail.com>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-abstract class google_auth_request extends curl {
-    protected $token = '';
-    private $persistantheaders = array();
-
-    // Must be overridden with the authorization header name
-    public static function get_auth_header_name() {
-        throw new coding_exception('get_auth_header_name() method needs to be overridden in each subclass of google_auth_request');
-    }
-
-    protected function request($url, $options = array()){
-        if($this->token){
-            // Adds authorisation head to a request so that it can be authentcated
-            $this->setHeader('Authorization: '. $this->get_auth_header_name().'"'.$this->token.'"');
-        }
-
-        foreach($this->persistantheaders as $h){
-            $this->setHeader($h);
-        }
-
-        $ret = parent::request($url, $options);
-        // reset headers for next request
-        $this->header = array();
-        return $ret;
-    }
-
-    protected function multi($requests, $options = array()) {
-        if($this->token){
-            // Adds authorisation head to a request so that it can be authentcated
-            $this->setHeader('Authorization: '. $this->get_auth_header_name().'"'.$this->token.'"');
-        }
-
-        foreach($this->persistantheaders as $h){
-            $this->setHeader($h);
-        }
-
-        $ret = parent::multi($requests, $options);
-        // reset headers for next request
-        $this->header = array();
-        return $ret;
-    }
-
-    public function get_sessiontoken(){
-        return $this->token;
-    }
-
-    public function add_persistant_header($header){
-        $this->persistantheaders[] = $header;
-    }
-}
-
-/*******
- * The following two classes are usd to implement AuthSub google
- * authtentication, as documented here:
- * http://code.google.com/apis/accounts/docs/AuthSub.html
- *******/
-
-/**
- * Used to uprade a google AuthSubRequest one-time token into
- * a session token which can be used long term.
+ * Class for manipulating google documents through the google data api.
  *
- * @package    moodlecore
- * @subpackage lib
- * @copyright Dan Poltawski <talktodan@gmail.com>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class google_authsub_request extends google_auth_request {
-    const AUTHSESSION_URL = 'https://www.google.com/accounts/AuthSubSessionToken';
-
-    /**
-     * Constructor. Calls constructor of its parents
-     *
-     * @param string $authtoken The token to upgrade to a session token
-     */
-    public function __construct($authtoken){
-        parent::__construct();
-        $this->token = $authtoken;
-    }
-
-    /**
-     * Requests a long-term session token from google based on the
-     *
-     * @return string Sub-Auth token
-     */
-    public function get_session_token(){
-        $content = $this->get(google_authsub_request::AUTHSESSION_URL);
-
-        if( preg_match('/token=(.*)/i', $content, $matches) ){
-            return $matches[1];
-        }else{
-            throw new moodle_exception('could not upgrade google authtoken to session token');
-        }
-    }
-
-    public static function get_auth_header_name(){
-        return 'AuthSub token=';
-    }
-}
-
-/**
- * Allows http calls using google subauth authorisation
- *
- * @package    moodlecore
- * @subpackage lib
- * @copyright Dan Poltawski <talktodan@gmail.com>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class google_authsub extends google_auth_request {
-    const LOGINAUTH_URL    = 'https://www.google.com/accounts/AuthSubRequest';
-    const VERIFY_TOKEN_URL = 'https://www.google.com/accounts/AuthSubTokenInfo';
-    const REVOKE_TOKEN_URL = 'https://www.google.com/accounts/AuthSubRevokeToken';
-
-    /**
-     * Constructor, allows subauth requests using the response from an initial
-     * AuthSubRequest or with the subauth long-term token. Note that constructing
-     * this object without a valid token will cause an exception to be thrown.
-     *
-     * @param string $sessiontoken A long-term subauth session token
-     * @param string $authtoken A one-time auth token wich is used to upgrade to session token
-     * @param mixed  @options Options to pass to the base curl object
-     */
-    public function __construct($sessiontoken = '', $authtoken = '', $options = array()){
-        parent::__construct($options);
-
-        if( $authtoken ){
-            $gauth = new google_authsub_request($authtoken);
-            $sessiontoken = $gauth->get_session_token();
-        }
-
-        $this->token = $sessiontoken;
-        if(! $this->valid_token() ){
-            throw new moodle_exception('Invalid subauth token');
-        }
-    }
-
-    /**
-     * Tests if a subauth token used is valid
-     *
-     * @return boolean true if token valid
-     */
-    public function valid_token(){
-        $this->get(google_authsub::VERIFY_TOKEN_URL);
-
-        if($this->info['http_code'] === 200){
-            return true;
-        }else{
-            return false;
-        }
-    }
-
-    /**
-     * Calls googles api to revoke the subauth token
-     *
-     * @return boolean Returns true if token succesfully revoked
-     */
-    public function revoke_session_token(){
-        $this->get(google_authsub::REVOKE_TOKEN_URL);
-
-        if($this->info['http_code'] === 200){
-            $this->token = '';
-            return true;
-        }else{
-            return false;
-        }
-    }
-
-    /**
-     * Creates a login url for subauth request
-     *
-     * @param string $returnaddr The address which the user should be redirected to recieve the token
-     * @param string $realm The google realm which is access is being requested
-     * @return string URL to bounce the user to
-     */
-    public static function login_url($returnaddr, $realm){
-        $uri = google_authsub::LOGINAUTH_URL.'?next='
-            .urlencode($returnaddr)
-            .'&scope='
-            .urlencode($realm)
-            .'&session=1&secure=0';
-
-        return $uri;
-    }
-
-    public static function get_auth_header_name(){
-        return 'AuthSub token=';
-    }
-}
-
-/**
- * Class for manipulating google documents through the google data api
  * Docs for this can be found here:
  * {@link http://code.google.com/apis/documents/docs/2.0/developers_guide_protocol.html}
  *
- * @package    moodlecore
+ * @package    core
  * @subpackage lib
  * @copyright Dan Poltawski <talktodan@gmail.com>
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class google_docs {
-    // need both docs and the spreadsheets realm
+    /** @var string Realm for authentication, need both docs and spreadsheet realm */
     const REALM            = 'https://docs.google.com/feeds/ https://spreadsheets.google.com/feeds/ https://docs.googleusercontent.com/';
+    /** @var string Document list url */
     const DOCUMENTFEED_URL = 'https://docs.google.com/feeds/default/private/full';
-    const USER_PREF_NAME   = 'google_authsub_sesskey';
+    /** @var string Upload url */
+    const UPLOAD_URL       = 'https://docs.google.com/feeds/upload/create-session/default/private/full?convert=false';
 
-    private $google_curl = null;
+    /** @var google_oauth oauth curl class for making authenticated requests */
+    private $googleoauth = null;
 
     /**
      * Constructor.
      *
-     * @param object A google_auth_request object which can be used to do http requests
+     * @param google_oauth $googleoauth oauth curl class for making authenticated requests
      */
-    public function __construct($google_curl){
-        if(is_a($google_curl, 'google_auth_request')){
-            $this->google_curl = $google_curl;
-            $this->google_curl->add_persistant_header('GData-Version: 3.0');
-        }else{
-            throw new moodle_exception('Google Curl Request object not given');
-        }
-    }
-
-    public static function get_sesskey($userid){
-        return get_user_preferences(google_docs::USER_PREF_NAME, false, $userid);
-    }
-
-    public static function set_sesskey($value, $userid){
-        return set_user_preference(google_docs::USER_PREF_NAME, $value, $userid);
-    }
-
-    public static function delete_sesskey($userid){
-        return unset_user_preference(google_docs::USER_PREF_NAME, $userid);
+    public function __construct(google_oauth $googleoauth) {
+        $this->googleoauth = $googleoauth;
+        $this->googleoauth->setHeader('GData-Version: 3.0');
     }
 
     /**
@@ -279,21 +65,19 @@ class google_docs {
      * @param string $search A search string to do full text search on the documents
      * @return mixed Array of files formated for fileapoi
      */
-    #FIXME
-    public function get_file_list($search = ''){
+    public function get_file_list($search = '') {
         global $CFG, $OUTPUT;
-        $url = google_docs::DOCUMENTFEED_URL;
+        $url = self::DOCUMENTFEED_URL;
 
-        if($search){
+        if ($search) {
             $url.='?q='.urlencode($search);
         }
-        $content = $this->google_curl->get($url);
+        $content = $this->googleoauth->get($url);
 
         $xml = new SimpleXMLElement($content);
 
-
         $files = array();
-        foreach($xml->entry as $gdoc){
+        foreach ($xml->entry as $gdoc) {
             $docid  = (string) $gdoc->children('http://schemas.google.com/g/2005')->resourceId;
             list($type, $docid) = explode(':', $docid);
 
@@ -325,7 +109,7 @@ class google_docs {
                     break;
             }
 
-            if(!empty($source)){
+            if (!empty($source)) {
                 $files[] =  array( 'title' => $title,
                     'url' => "{$gdoc->link[0]->attributes()->href}",
                     'source' => $source,
@@ -344,71 +128,98 @@ class google_docs {
      * @param object $file File object
      * @return boolean True on success
      */
-    public function send_file($file){
-        $this->google_curl->setHeader("Content-Length: ". $file->get_filesize());
-        $this->google_curl->setHeader("Content-Type: ". $file->get_mimetype());
-        $this->google_curl->setHeader("Slug: ". $file->get_filename());
+    public function send_file($file) {
+        // First we create the 'resumable upload request'.
+        $this->googleoauth->setHeader("Content-Length: 0");
+        $this->googleoauth->setHeader("X-Upload-Content-Length: ". $file->get_filesize());
+        $this->googleoauth->setHeader("X-Upload-Content-Type: ". $file->get_mimetype());
+        $this->googleoauth->setHeader("Slug: ". $file->get_filename());
+        $this->googleoauth->post(self::UPLOAD_URL);
+
+        if ($this->googleoauth->info['http_code'] !== 200) {
+            throw new moodle_exception('Cantpostupload');
+        }
+
+        // Now we http PUT the file in the location returned.
+        $location = $this->googleoauth->response['Location'];
+        if (empty($location)) {
+            throw new moodle_exception('Nouploadlocation');
+        }
+
+        // Reset the curl object for actually sending the file.
+        $this->googleoauth->clear_headers();
+        $this->googleoauth->setHeader("Content-Length: ". $file->get_filesize());
+        $this->googleoauth->setHeader("Content-Type: ". $file->get_mimetype());
+
+        // We can't get a filepointer, so have to copy the file..
+        $tmproot = make_temp_directory('googledocsuploads');
+        $tmpfilepath = $tmproot.'/'.$file->get_contenthash();
+        $file->copy_content_to($tmpfilepath);
 
-        $this->google_curl->post(google_docs::DOCUMENTFEED_URL, $file->get_content());
+        // HTTP PUT the file.
+        $this->googleoauth->put($location, array('file'=>$tmpfilepath));
 
-        if($this->google_curl->info['http_code'] === 201){
+        // Remove the temporary file we created..
+        unlink($tmpfilepath);
+
+        if ($this->googleoauth->info['http_code'] === 201) {
             return true;
-        }else{
+        } else {
             return false;
         }
     }
 
-    public function download_file($url, $fp){
-        return $this->google_curl->download(array( array('url'=>$url, 'file' => $fp) ));
+    /**
+     * Downloads a file using authentication
+     *
+     * @param string $url url of file
+     * @param string $path path to save file to
+     * @return array stucture for repository download_file
+     */
+    public function download_file($url, $path) {
+        $content = $this->googleoauth->get($url);
+        file_put_contents($path, $content);
+        return array('path'=>$path, 'url'=>$url);
     }
 }
 
 /**
- * Class for manipulating picasa through the google data api
+ * Class for manipulating picasa through the google data api.
+ *
  * Docs for this can be found here:
  * {@link http://code.google.com/apis/picasaweb/developers_guide_protocol.html}
  *
- * @package    moodlecore
- * @subpackage lib
+ * @package   core
  * @copyright Dan Poltawski <talktodan@gmail.com>
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class google_picasa {
+    /** @var string Realm for authentication */
     const REALM             = 'http://picasaweb.google.com/data/';
-    const USER_PREF_NAME    = 'google_authsub_sesskey_picasa';
+    /** @var string Upload url */
     const UPLOAD_LOCATION   = 'https://picasaweb.google.com/data/feed/api/user/default/albumid/default';
+    /** @var string photo list url */
     const ALBUM_PHOTO_LIST  = 'https://picasaweb.google.com/data/feed/api/user/default/albumid/';
+    /** @var string search url */
     const PHOTO_SEARCH_URL  = 'https://picasaweb.google.com/data/feed/api/user/default?kind=photo&q=';
+    /** @var string album list url */
     const LIST_ALBUMS_URL   = 'https://picasaweb.google.com/data/feed/api/user/default';
+    /** @var string manage files url */
     const MANAGE_URL        = 'http://picasaweb.google.com/';
 
-    private $google_curl = null;
+    /** @var google_oauth oauth curl class for making authenticated requests */
+    private $googleoauth = null;
+    /** @var string Last album name retrievied */
     private $lastalbumname = null;
 
     /**
      * Constructor.
      *
-     * @param object A google_auth_request object which can be used to do http requests
+     * @param google_oauth $googleoauth oauth curl class for making authenticated requests
      */
-    public function __construct($google_curl){
-        if(is_a($google_curl, 'google_auth_request')){
-            $this->google_curl = $google_curl;
-            $this->google_curl->add_persistant_header('GData-Version: 2');
-        }else{
-            throw new moodle_exception('Google Curl Request object not given');
-        }
-    }
-
-    public static function get_sesskey($userid){
-        return get_user_preferences(google_picasa::USER_PREF_NAME, false, $userid);
-    }
-
-    public static function set_sesskey($value, $userid){
-        return set_user_preference(google_picasa::USER_PREF_NAME, $value, $userid);
-    }
-
-    public static function delete_sesskey($userid){
-        return unset_user_preference(google_picasa::USER_PREF_NAME, $userid);
+    public function __construct(google_oauth $googleoauth) {
+        $this->googleoauth = $googleoauth;
+        $this->googleoauth->setHeader('GData-Version: 2');
     }
 
     /**
@@ -417,16 +228,16 @@ class google_picasa {
      * @param object $file File object
      * @return boolean True on success
      */
-    public function send_file($file){
-        $this->google_curl->setHeader("Content-Length: ". $file->get_filesize());
-        $this->google_curl->setHeader("Content-Type: ". $file->get_mimetype());
-        $this->google_curl->setHeader("Slug: ". $file->get_filename());
+    public function send_file($file) {
+        $this->googleoauth->setHeader("Content-Length: ". $file->get_filesize());
+        $this->googleoauth->setHeader("Content-Type: ". $file->get_mimetype());
+        $this->googleoauth->setHeader("Slug: ". $file->get_filename());
 
-        $this->google_curl->post(google_picasa::UPLOAD_LOCATION, $file->get_content());
+        $this->googleoauth->post(self::UPLOAD_LOCATION, $file->get_content());
 
-        if($this->google_curl->info['http_code'] === 201){
+        if ($this->googleoauth->info['http_code'] === 201) {
             return true;
-        }else{
+        } else {
             return false;
         }
     }
@@ -439,10 +250,10 @@ class google_picasa {
      * @param string $path The path to files (assumed to be albumid)
      * @return mixed $files A list of files for the file picker
      */
-    public function get_file_list($path = ''){
-        if(!$path){
+    public function get_file_list($path = '') {
+        if (!$path) {
             return $this->get_albums();
-        }else{
+        } else {
             return $this->get_album_photos($path);
         }
     }
@@ -453,8 +264,8 @@ class google_picasa {
      * @param int $albumid Photo album to list photos from
      * @return mixed $files A list of files for the file picker
      */
-    public function get_album_photos($albumid){
-        $albumcontent = $this->google_curl->get(google_picasa::ALBUM_PHOTO_LIST.$albumid);
+    public function get_album_photos($albumid) {
+        $albumcontent = $this->googleoauth->get(self::ALBUM_PHOTO_LIST.$albumid);
 
         return $this->get_photo_details($albumcontent);
     }
@@ -475,8 +286,8 @@ class google_picasa {
      * @param string $query Search terms
      * @return mixed $files A list of files for the file picker
      */
-    public function do_photo_search($query){
-        $content = $this->google_curl->get(google_picasa::PHOTO_SEARCH_URL.htmlentities($query));
+    public function do_photo_search($query) {
+        $content = $this->googleoauth->get(self::PHOTO_SEARCH_URL.htmlentities($query));
 
         return $this->get_photo_details($content);
     }
@@ -487,17 +298,17 @@ class google_picasa {
      *
      * @return mixes $files Array in the format get_listing uses for folders
      */
-    public function get_albums(){
-        $content = $this->google_curl->get(google_picasa::LIST_ALBUMS_URL);
+    public function get_albums() {
+        $content = $this->googleoauth->get(self::LIST_ALBUMS_URL);
         $xml = new SimpleXMLElement($content);
 
         $files = array();
 
-        foreach($xml->entry as $album){
+        foreach ($xml->entry as $album) {
             $gphoto = $album->children('http://schemas.google.com/photos/2007');
 
             $mediainfo = $album->children('http://search.yahoo.com/mrss/');
-            //hacky...
+            // Hacky...
             $thumbnailinfo = $mediainfo->group->thumbnail[0]->attributes();
 
             $files[] = array( 'title' => (string) $album->title,
@@ -505,7 +316,7 @@ class google_picasa {
                 'size'  => (int) $gphoto->bytesUsed,
                 'path'  => (string) $gphoto->id,
                 'thumbnail' => (string) $thumbnailinfo['url'],
-                'thumbnail_width' => 160,  // 160 is the native maximum dimension
+                'thumbnail_width' => 160,  // 160 is the native maximum dimension.
                 'thumbnail_height' => 160,
                 'children' => array(),
             );
@@ -522,22 +333,22 @@ class google_picasa {
      * @param string $rawxml XML from picasa api
      * @return mixed $files A list of files for the file picker
      */
-    public function get_photo_details($rawxml){
+    public function get_photo_details($rawxml) {
 
         $xml = new SimpleXMLElement($rawxml);
         $this->lastalbumname = (string)$xml->title;
 
         $files = array();
 
-        foreach($xml->entry as $photo){
+        foreach ($xml->entry as $photo) {
             $gphoto = $photo->children('http://schemas.google.com/photos/2007');
 
             $mediainfo = $photo->children('http://search.yahoo.com/mrss/');
             $fullinfo = $mediainfo->group->content->attributes();
-            //hacky...
+            // Hacky...
             $thumbnailinfo = $mediainfo->group->thumbnail[0]->attributes();
 
-            // Derive the nicest file name we can
+            // Derive the nicest file name we can.
             if (!empty($mediainfo->group->description)) {
                 $title = shorten_text((string)$mediainfo->group->description, 20, false, '');
                 $title = clean_filename($title).'.jpg';
@@ -551,7 +362,7 @@ class google_picasa {
                 'size' => (int) $gphoto->size,
                 'path' => $gphoto->albumid.'/'.$gphoto->id,
                 'thumbnail' => (string) $thumbnailinfo['url'],
-                'thumbnail_width' => 72,  // 72 is the native maximum dimension
+                'thumbnail_width' => 72,  // 72 is the native maximum dimension.
                 'thumbnail_height' => 72,
                 'source' => (string) $fullinfo['url'],
                 'url' => (string) $fullinfo['url']
@@ -560,54 +371,36 @@ class google_picasa {
 
         return $files;
     }
-
 }
 
 /**
- * Beginings of an implementation of Clientogin authenticaton for google
- * accounts as documented here:
- * {@link http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#ClientLogin}
+ * OAuth 2.0 client for Google Services
  *
- * With this authentication we have to accept a username and password and to post
- * it to google. Retrieving a token for use afterwards.
- *
- * @package    moodlecore
- * @subpackage lib
- * @copyright Dan Poltawski <talktodan@gmail.com>
+ * @package   core
+ * @copyright 2012 Dan Poltawski
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class google_authclient extends google_auth_request {
-    const LOGIN_URL = 'https://www.google.com/accounts/ClientLogin';
-
-    public function __construct($sessiontoken = '', $username = '', $password = '', $options = array() ){
-        parent::__construct($options);
-
-        if($username and $password){
-            $param =  array(
-                'accountType'=>'GOOGLE',
-                'Email'=>$username,
-                'Passwd'=>$password,
-                'service'=>'writely'
-            );
-
-            $content = $this->post(google_authclient::LOGIN_URL, $param);
-
-            if( preg_match('/auth=(.*)/i', $content, $matches) ){
-                $sessiontoken = $matches[1];
-            }else{
-                throw new moodle_exception('could not upgrade authtoken');
-            }
-
-        }
+class google_oauth extends oauth2_client {
+    /**
+     * Returns the auth url for OAuth 2.0 request
+     * @return string the auth url
+     */
+    protected function auth_url() {
+        return 'https://accounts.google.com/o/oauth2/auth';
+    }
 
-        if($sessiontoken){
-            $this->token = $sessiontoken;
-        }else{
-            throw new moodle_exception('no session token specified');
-        }
+    /**
+     * Returns the token url for OAuth 2.0 request
+     * @return string the auth url
+     */
+    protected function token_url() {
+        return 'https://accounts.google.com/o/oauth2/token';
     }
 
-    public static function get_auth_header_name(){
-        return 'GoogleLogin auth=';
+    /**
+     * Clear any headers in the curl object
+     */
+    public function clear_headers() {
+        $this->header = array();
     }
 }
index f1c9262..0fb864d 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['clientid'] = 'Client ID';
+$string['oauthinfo'] = '<p>To use the google docs portfolio you must be registered with Google. Instructions for registing your installation with Google are described in <a href="{$a->docsurl}">Moodle Docs</a>. The redirect url should be set to:</p><p>{$a->callbackurl}</p>';
 $string['noauthtoken'] = 'An authentication token has not been recieved from google. Please ensure you are allowing moodle to access your google account';
 $string['nosessiontoken'] = 'A session token does not exist preventing export to google.';
 $string['pluginname'] = 'Google Docs';
 $string['sendfailed'] = 'The file {$a} failed to transfer to google';
+$string['secret'] = 'Secret';
index 2223f9d..c641f09 100644 (file)
@@ -1,4 +1,19 @@
 <?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
 /**
  * Google Documents Portfolio Plugin
  *
@@ -9,18 +24,10 @@ require_once($CFG->libdir.'/portfolio/plugin.php');
 require_once($CFG->libdir.'/googleapi.php');
 
 class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
-    private $sessiontoken;
+    private $googleoauth = null;
 
     public function supported_formats() {
-        return array(
-            PORTFOLIO_FORMAT_PLAINHTML,
-            PORTFOLIO_FORMAT_IMAGE,
-            PORTFOLIO_FORMAT_TEXT,
-            PORTFOLIO_FORMAT_PDF,
-            PORTFOLIO_FORMAT_DOCUMENT,
-            PORTFOLIO_FORMAT_PRESENTATION,
-            PORTFOLIO_FORMAT_SPREADSHEET
-        );
+        return array(PORTFOLIO_FORMAT_FILE);
     }
 
     public static function get_name() {
@@ -28,29 +35,27 @@ class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
     }
 
     public function prepare_package() {
-        // we send the files as they are, no prep required
+        // We send the files as they are, no prep required.
         return true;
     }
 
-    public function get_interactive_continue_url(){
+    public function get_interactive_continue_url() {
         return 'http://docs.google.com/';
     }
 
     public function expected_time($callertime) {
-        // we trust what the portfolio says
+        // We trust what the portfolio says.
         return $callertime;
     }
 
     public function send_package() {
-
-        if(!$this->sessiontoken){
-            throw new portfolio_plugin_exception('nosessiontoken', 'portfolio_googledocs');
+        if (!$this->googleoauth) {
+            throw new portfolio_plugin_exception('noauthtoken', 'portfolio_googledocs');
         }
 
-        $gdocs = new google_docs(new google_authsub($this->sessiontoken));
-
+        $gdocs = new google_docs($this->googleoauth);
         foreach ($this->exporter->get_tempfiles() as $file) {
-            if(!$gdocs->send_file($file)){
+            if (!$gdocs->send_file($file)) {
                 throw new portfolio_plugin_exception('sendfailed', 'portfolio_gdocs', $file->get_filename());
             }
         }
@@ -62,20 +67,12 @@ class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
             return false;
         }
 
-        $sesskey = google_docs::get_sesskey($this->get('user')->id);
-
-        if($sesskey){
-            try{
-                $gauth = new google_authsub($sesskey);
-                $this->sessiontoken = $sesskey;
-                return false;
-            }catch(Exception $e){
-                // sesskey is not valid, delete store and re-auth
-                google_docs::delete_sesskey($this->get('user')->id);
-            }
+        $this->initialize_oauth();
+        if ($this->googleoauth->is_logged_in()) {
+            return false;
+        } else {
+            return $this->googleoauth->get_login_url();
         }
-
-        return google_authsub::login_url($CFG->wwwroot.'/portfolio/add.php?postcontrol=1&id=' . $this->exporter->get('id') . '&sesskey=' . sesskey(), google_docs::REALM);
     }
 
     public function post_control($stage, $params) {
@@ -83,43 +80,50 @@ class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
             return;
         }
 
-        if(!array_key_exists('token', $params)){
-            throw new portfolio_plugin_exception('noauthtoken', 'portfolio_googledocs');
+        $this->initialize_oauth();
+        if ($this->googleoauth->is_logged_in()) {
+            return false;
+        } else {
+            return $this->googleoauth->get_login_url();
         }
-
-        // we now have our auth token, get a session token..
-        $gauth = new google_authsub(false, $params['token']);
-        $this->sessiontoken = $gauth->get_sessiontoken();
-
-        google_docs::set_sesskey($this->sessiontoken, $this->get('user')->id);
     }
 
     public static function allows_multiple_instances() {
         return false;
     }
-}
 
-/**
- * Registers to the user_deleted event to revoke any
- * subauth tokens we have from them
- *
- * @param $user user object
- * @return boolean true in all cases as its only minor cleanup
- */
-function portfolio_googledocs_user_deleted($user){
-    // it is only by luck that the user prefstill exists now?
-    // We probably need a pre-delete event?
-    if($sesskey = google_docs::get_sesskey($user->id)){
-        try{
-            $gauth = new google_authsub($sesskey);
-
-            $gauth->revoke_session_token();
-        }catch(Exception $e){
-            // we don't care that much about success- just being good
-            // google api citzens
-            return true;
-        }
+    public static function has_admin_config() {
+        return true;
+    }
+
+    public static function get_allowed_config() {
+        return array('clientid', 'secret');
+    }
+
+    public function admin_config_form(&$mform) {
+        $a = new stdClass;
+        $a->docsurl = get_docs_url('Google_OAuth2_Setup');
+        $a->callbackurl = google_oauth::callback_url()->out(false);
+
+        $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_googledocs', $a));
+
+        $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_googledocs'));
+        $mform->addElement('text', 'secret', get_string('secret', 'portfolio_googledocs'));
+
+        $strrequired = get_string('required');
+        $mform->addRule('clientid', $strrequired, 'required', null, 'client');
+        $mform->addRule('secret', $strrequired, 'required', null, 'client');
     }
 
-    return true;
+    private function initialize_oauth() {
+        $returnurl = new moodle_url('/portfolio/add.php');
+        $returnurl->param('postcontrol', 1);
+        $returnurl->param('id', $this->exporter->get('id'));
+        $returnurl->param('sesskey', sesskey());
+
+        $clientid = $this->get_config('clientid');
+        $secret = $this->get_config('secret');
+
+        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl->out(false), google_docs::REALM);
+    }
 }
index 2044666..a64c628 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2011112900;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2011112900;        // Requires this Moodle version
-$plugin->component = 'portfolio_googledocs'; // Full name of the plugin (used for diagnostics)
+$plugin->version   = 2012051400;        // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2012051100;        // Requires this Moodle version.
+$plugin->component = 'portfolio_googledocs'; // Full name of the plugin (used for diagnostics).
 $plugin->cron      = 0;
index fec154b..10c12e6 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -23,6 +22,9 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['clientid'] = 'Client ID';
+$string['oauthinfo'] = '<p>To use the Picasa portfolio you must be registered with Google. Instructions for registing your installation with Google are described in <a href="{$a->docsurl}">Moodle Docs</a>. The redirect url should be set to:</p><p>{$a->callbackurl}</p>';
 $string['noauthtoken'] = 'An authentication token has not been recieved from google. Please ensure you are allowing moodle to access your google account';
 $string['pluginname'] = 'Picasa';
 $string['sendfailed'] = 'The file {$a} failed to transfer to picasa';
+$string['secret'] = 'Secret';
index a9ba23f..6d21336 100644 (file)
@@ -1,4 +1,19 @@
 <?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
 /**
  * Picasa Portfolio Plugin
  *
@@ -9,7 +24,7 @@ require_once($CFG->libdir.'/portfolio/plugin.php');
 require_once($CFG->libdir.'/googleapi.php');
 
 class portfolio_plugin_picasa extends portfolio_plugin_push_base {
-    private $sessionkey;
+    private $googleoauth = null;
 
     public function supported_formats() {
         return array(PORTFOLIO_FORMAT_IMAGE, PORTFOLIO_FORMAT_VIDEO);
@@ -20,11 +35,11 @@ class portfolio_plugin_picasa extends portfolio_plugin_push_base {
     }
 
     public function prepare_package() {
-        // we send the files as they are, no prep required
+        // We send the files as they are, no prep required.
         return true;
     }
 
-    public function get_interactive_continue_url(){
+    public function get_interactive_continue_url() {
         return 'http://picasaweb.google.com/';
     }
 
@@ -33,40 +48,31 @@ class portfolio_plugin_picasa extends portfolio_plugin_push_base {
     }
 
     public function send_package() {
-        if(!$this->sessionkey){
+        if (!$this->googleoauth) {
             throw new portfolio_plugin_exception('noauthtoken', 'portfolio_picasa');
         }
 
-        $picasa = new google_picasa(new google_authsub($this->sessionkey));
-
+        $picasa = new google_picasa($this->googleoauth);
         foreach ($this->exporter->get_tempfiles() as $file) {
 
-            if(!$picasa->send_file($file)){
+            if (!$picasa->send_file($file)) {
                 throw new portfolio_plugin_exception('sendfailed', 'portfolio_picasa', $file->get_filename());
             }
         }
     }
 
     public function steal_control($stage) {
-        global $CFG;
         if ($stage != PORTFOLIO_STAGE_CONFIG) {
             return false;
         }
 
-        $sesskey = google_picasa::get_sesskey($this->get('user')->id);
+        $this->initialize_oauth();
 
-        if($sesskey){
-            try{
-                $gauth = new google_authsub($sesskey);
-                $this->sessionkey = $sesskey;
-                return false;
-            }catch(Exception $e){
-                // sesskey is not valid, delete store and re-auth
-                google_picasa::delete_sesskey($this->get('user')->id);
-            }
+        if ($this->googleoauth->is_logged_in()) {
+            return false;
+        } else {
+            return $this->googleoauth->get_login_url();
         }
-
-        return google_authsub::login_url($CFG->wwwroot.'/portfolio/add.php?postcontrol=1&id=' . $this->exporter->get('id') . '&sesskey=' . sesskey(), google_picasa::REALM);
     }
 
     public function post_control($stage, $params) {
@@ -74,44 +80,50 @@ class portfolio_plugin_picasa extends portfolio_plugin_push_base {
             return;
         }
 
-        if(!array_key_exists('token', $params)){
-            throw new portfolio_plugin_exception('noauthtoken', 'portfolio_picasa');
+        $this->initialize_oauth();
+        if ($this->googleoauth->is_logged_in()) {
+            return false;
+        } else {
+            return $this->googleoauth->get_login_url();
         }
+    }
 
-        // we now have our auth token, get a session token..
-        $gauth = new google_authsub(false, $params['token']);
-
-        $this->sessionkey = $gauth->get_sessiontoken();
-
-        google_picasa::set_sesskey($this->sessionkey, $this->get('user')->id);
+    public static function has_admin_config() {
+        return true;
     }
 
     public static function allows_multiple_instances() {
         return false;
     }
-}
 
-/**
- * Registers to the user_deleted event to revoke any
- * subauth tokens we have from them
- *
- * @param $user user object
- * @return boolean true in all cases as its only minor cleanup
- */
-function portfolio_picasa_user_deleted($user){
-    // it is only by luck that the user prefstill exists now?
-    // We probably need a pre-delete event?
-    if($sesskey = google_picasa::get_sesskey($user->id)){
-        try{
-            $gauth = new google_authsub($sesskey);
-
-            $gauth->revoke_session_token();
-        }catch(Exception $e){
-            // we don't care that much about success- just being good
-            // google api citzens
-            return true;
-        }
+    public static function get_allowed_config() {
+        return array('clientid', 'secret');
+    }
+
+    public function admin_config_form(&$mform) {
+        $a = new stdClass;
+        $a->docsurl = get_docs_url('Google_OAuth2_Setup');
+        $a->callbackurl = google_oauth::callback_url()->out(false);
+
+        $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_picasa', $a));
+
+        $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_picasa'));
+        $mform->addElement('text', 'secret', get_string('secret', 'portfolio_picasa'));
+
+        $strrequired = get_string('required');
+        $mform->addRule('clientid', $strrequired, 'required', null, 'client');
+        $mform->addRule('secret', $strrequired, 'required', null, 'client');
     }
 
-    return true;
+    private function initialize_oauth() {
+        $returnurl = new moodle_url('/portfolio/add.php');
+        $returnurl->param('postcontrol', 1);
+        $returnurl->param('id', $this->exporter->get('id'));
+        $returnurl->param('sesskey', sesskey());
+
+        $clientid = $this->get_config('clientid');
+        $secret = $this->get_config('secret');
+
+        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl->out(false), google_picasa::REALM);
+    }
 }
index 7906a25..113c9cf 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2011112900;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2011112900;        // Requires this Moodle version
-$plugin->component = 'portfolio_picasa'; // Full name of the plugin (used for diagnostics)
+$plugin->version   = 2012051400;        // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2012051100;        // Requires this Moodle version.
+$plugin->component = 'portfolio_picasa'; // Full name of the plugin (used for diagnostics).
 $plugin->cron      = 0;
similarity index 58%
rename from portfolio/picasa/db/events.php
rename to repository/googledocs/db/upgrade.php
index 09ef7cc..76876a1 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Add event handlers for the picasa portfolio.
- *
- * @package    portfolio_picasa
- * @category   event
- * @copyright  2009 Penny Leach
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @param int $oldversion the version we are upgrading from
+ * @return bool result
  */
+function xmldb_repository_googledocs_upgrade($oldversion) {
+    global $CFG, $DB;
 
-$handlers = array (
-    'user_deleted' => array (
-         'handlerfile'      => '/portfolio/picasa/lib.php',
-         'handlerfunction'  => 'portfolio_picasa_user_deleted',
-         'schedule'         => 'cron',
-         'internal'         => 0,
-     ),
-);
\ No newline at end of file
+    $dbman = $DB->get_manager();
+
+    if ($oldversion < 2012051400) {
+        // Delete old user preferences containing authsub tokens.
+        $DB->delete_records('user_preferences', array('name' => 'google_authsub_sesskey'));
+        upgrade_plugin_savepoint(true, 2012051400, 'repository', 'googledocs');
+    }
+
+    return true;
+}
index 38f1436..8e8cf80 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['clientid'] = 'Client ID';
+$string['configplugin'] = 'Configure Google Docs plugin';
 $string['googledocs:view'] = 'View google docs repository';
+$string['oauthinfo'] = '<p>To use the Google Docs repository you must be registered with Google. Instructions for registing your installation with Google are described in <a href="{$a->docsurl}">Moodle Docs</a>. The redirect url should be set to:</p><p>{$a->callbackurl}</p>';
 $string['pluginname'] = 'Google Docs';
-$string['configplugin'] = 'Configurate Google Docs plugin';
+$string['secret'] = 'Secret';
+
index 36648bd..6ccb33b 100644 (file)
@@ -34,55 +34,40 @@ require_once($CFG->libdir.'/googleapi.php');
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class repository_googledocs extends repository {
-    private $subauthtoken = '';
+    private $googleoauth = null;
 
     public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
-        global $USER;
         parent::__construct($repositoryid, $context, $options);
 
-        // TODO: I wish there was somewhere we could explicitly put this outside of constructor..
-        $googletoken = optional_param('token', false, PARAM_RAW);
-        if($googletoken){
-            $gauth = new google_authsub(false, $googletoken); // will throw exception if fails
-            google_docs::set_sesskey($gauth->get_sessiontoken(), $USER->id);
-        }
+        $returnurl = new moodle_url('/repository/repository_callback.php',
+            array('callback' => 'yes', 'repo_id' =>$this->id));
+
+        $clientid = get_config('googledocs', 'clientid');
+        $secret = get_config('googledocs', 'secret');
+        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl->out(false), google_docs::REALM);
+
         $this->check_login();
     }
 
     public function check_login() {
-        global $USER;
-
-        $sesskey = google_docs::get_sesskey($USER->id);
-
-        if($sesskey){
-            try{
-                $gauth = new google_authsub($sesskey);
-                $this->subauthtoken = $sesskey;
-                return true;
-            }catch(Exception $e){
-                // sesskey is not valid, delete store and re-auth
-                google_docs::delete_sesskey($USER->id);
-            }
-        }
-
-        return false;
+        return $this->googleoauth->is_logged_in();
     }
 
-    public function print_login($ajax = true){
-        global $CFG;
-        if($ajax){
-            $ret = array();
-            $popup_btn = new stdClass();
-            $popup_btn->type = 'popup';
-            $returnurl = $CFG->wwwroot.'/repository/repository_callback.php?callback=yes&repo_id='.$this->id;
-            $popup_btn->url = google_authsub::login_url($returnurl, google_docs::REALM);
-            $ret['login'] = array($popup_btn);
-            return $ret;
+    public function print_login({
+        $url = $this->googleoauth->get_login_url();
+
+        if ($this->options['ajax']) {
+            $popup = new stdClass();
+            $popup->type = 'popup';
+            $popup->url = $url->out(false);
+            return array('login' => array($popup));
+        } else {
+            echo '<a target="_blank" href="'.$url->out(false).'">'.get_string('login', 'repository').'</a>';
         }
     }
 
     public function get_listing($path='', $page = '') {
-        $gdocs = new google_docs(new google_authsub($this->subauthtoken));
+        $gdocs = new google_docs($this->googleoauth);
 
         $ret = array();
         $ret['dynload'] = true;
@@ -91,7 +76,7 @@ class repository_googledocs extends repository {
     }
 
     public function search($search_text, $page = 0) {
-        $gdocs = new google_docs(new google_authsub($this->subauthtoken));
+        $gdocs = new google_docs($this->googleoauth);
 
         $ret = array();
         $ret['dynload'] = true;
@@ -99,37 +84,44 @@ class repository_googledocs extends repository {
         return $ret;
     }
 
-    public function logout(){
-        global $USER;
-
-        $token = google_docs::get_sesskey($USER->id);
-
-        $gauth = new google_authsub($token);
-        // revoke token from google
-        $gauth->revoke_session_token();
-
-        google_docs::delete_sesskey($USER->id);
-        $this->subauthtoken = '';
-
+    public function logout() {
+        $this->googleoauth->log_out();
         return parent::logout();
     }
 
     public function get_file($url, $file = '') {
-        global $CFG;
-        $path = $this->prepare_file($file);
+        $gdocs = new google_docs($this->googleoauth);
 
-        $fp = fopen($path, 'w');
-        $gdocs = new google_docs(new google_authsub($this->subauthtoken));
-        $gdocs->download_file($url, $fp);
-
-        return array('path'=>$path, 'url'=>$url);
+        $path = $this->prepare_file($file);
+        return $gdocs->download_file($url, $path);
     }
 
     public function supported_filetypes() {
-       return array('document');
+        return '*';
     }
     public function supported_returntypes() {
         return FILE_INTERNAL;
     }
+
+    public static function get_type_option_names() {
+        return array('clientid', 'secret', 'pluginname');
+    }
+
+    public static function type_config_form($mform, $classname = 'repository') {
+
+        $a = new stdClass;
+        $a->docsurl = get_docs_url('Google_OAuth2_Setup');
+        $a->callbackurl = google_oauth::callback_url()->out(false);
+
+        $mform->addElement('static', null, '', get_string('oauthinfo', 'repository_googledocs', $a));
+
+        parent::type_config_form($mform);
+        $mform->addElement('text', 'clientid', get_string('clientid', 'repository_googledocs'));
+        $mform->addElement('text', 'secret', get_string('secret', 'repository_googledocs'));
+
+        $strrequired = get_string('required');
+        $mform->addRule('clientid', $strrequired, 'required', null, 'client');
+        $mform->addRule('secret', $strrequired, 'required', null, 'client');
+    }
 }
-//Icon from: http://www.iconspedia.com/icon/google-2706.html
+// Icon from: http://www.iconspedia.com/icon/google-2706.html.
index 79c6db7..7269aa5 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2011112900;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2011112900;        // Requires this Moodle version
-$plugin->component = 'repository_googledocs'; // Full name of the plugin (used for diagnostics)
+$plugin->version   = 2012051400;        // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2012051100;        // Requires this Moodle version.
+$plugin->component = 'repository_googledocs'; // Full name of the plugin (used for diagnostics).
similarity index 58%
rename from portfolio/googledocs/db/events.php
rename to repository/picasa/db/upgrade.php
index b0d3d0c..545ce3b 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Add event handlers for the googledocs portfolio.
- *
- * @package    portfolio_googledocs
- * @category   event
- * @copyright  2009 Penny Leach
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @param int $oldversion the version we are upgrading from
+ * @return bool result
  */
+function xmldb_repository_picasa_upgrade($oldversion) {
+    global $CFG, $DB;
 
-$handlers = array (
-    'user_deleted' => array (
-         'handlerfile'      => '/portfolio/googledocs/lib.php',
-         'handlerfunction'  => 'portfolio_googledocs_user_deleted',
-         'schedule'         => 'cron',
-         'internal'         => 0,
-     ),
-);
+    $dbman = $DB->get_manager();
 
+    if ($oldversion < 2012051400) {
+        // Delete old user preferences storing authsub tokens.
+        $DB->delete_records('user_preferences', array('name' => 'google_authsub_sesskey_picasa'));
+        upgrade_plugin_savepoint(true, 2012051400, 'repository', 'picasa');
+    }
 
+    return true;
+}
index 23d9dbe..3c03022 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -23,6 +22,9 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['clientid'] = 'Client ID';
+$string['configplugin'] = 'Picasa repository configuration';
+$string['oauthinfo'] = '<p>To use the Picasa repository you must be registered with Google. Instructions for registing your installation with Google are described in <a href="{$a->docsurl}">Moodle Docs</a>. The redirect url should be set to:</p><p>{$a->callbackurl}</p>';
 $string['picasa:view'] = 'View picasa repository';
 $string['pluginname'] = 'Picasa web album';
-$string['configplugin'] = 'Picasa repository configuration';
+$string['secret'] = 'Secret';
index 6a83ca0..9022380 100644 (file)
@@ -36,58 +36,40 @@ require_once($CFG->libdir.'/googleapi.php');
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class repository_picasa extends repository {
-    private $subauthtoken = '';
+    private $googleoauth = null;
 
     public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
-        global $USER;
         parent::__construct($repositoryid, $context, $options);
 
-        // TODO: I wish there was somewhere we could explicitly put this outside of constructor..
-        $googletoken = optional_param('token', false, PARAM_RAW);
-        if($googletoken){
-            $gauth = new google_authsub(false, $googletoken); // will throw exception if fails
-            google_picasa::set_sesskey($gauth->get_sessiontoken(), $USER->id);
-        }
+        $returnurl = new moodle_url('/repository/repository_callback.php',
+            array('callback' => 'yes', 'repo_id' =>$this->id));
+
+        $clientid = get_config('picasa', 'clientid');
+        $secret = get_config('picasa', 'secret');
+        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl->out(false), google_picasa::REALM);
+
         $this->check_login();
     }
 
     public function check_login() {
-        global $USER;
-
-        $sesskey = google_picasa::get_sesskey($USER->id);
-
-        if($sesskey){
-            try{
-                $gauth = new google_authsub($sesskey);
-                $this->subauthtoken = $sesskey;
-                return true;
-            }catch(Exception $e){
-                // sesskey is not valid, delete store and re-auth
-                google_picasa::delete_sesskey($USER->id);
-            }
-        }
-
-        return false;
+        return $this->googleoauth->is_logged_in();
     }
 
-    public function print_login(){
-        global $CFG;
-        $returnurl = $CFG->wwwroot.'/repository/repository_callback.php?callback=yes&repo_id='.$this->id;
-        $authurl = google_authsub::login_url($returnurl, google_picasa::REALM);
-        if($this->options['ajax']){
-            $ret = array();
-            $popup_btn = new stdClass();
-            $popup_btn->type = 'popup';
-            $popup_btn->url = $authurl;
-            $ret['login'] = array($popup_btn);
-            return $ret;
+    public function print_login() {
+        $url = $this->googleoauth->get_login_url();
+
+        if ($this->options['ajax']) {
+            $popup = new stdClass();
+            $popup->type = 'popup';
+            $popup->url = $url->out(false);
+            return array('login' => array($popup));
         } else {
-            echo '<a target="_blank" href="'.$authurl.'">Login</a>';
+            echo '<a target="_blank" href="'.$url->out(false).'">'.get_string('login', 'repository').'</a>';
         }
     }
 
     public function get_listing($path='', $page = '') {
-        $picasa = new google_picasa(new google_authsub($this->subauthtoken));
+        $picasa = new google_picasa($this->googleoauth);
 
         $ret = array();
         $ret['dynload'] = true;
@@ -101,7 +83,7 @@ class repository_picasa extends repository {
     }
 
     public function search($search_text, $page = 0) {
-        $picasa = new google_picasa(new google_authsub($this->subauthtoken));
+        $picasa = new google_picasa($this->googleoauth);
 
         $ret = array();
         $ret['manage'] = google_picasa::MANAGE_URL;
@@ -109,22 +91,12 @@ class repository_picasa extends repository {
         return $ret;
     }
 
-    public function logout(){
-        global $USER;
-
-        $token = google_picasa::get_sesskey($USER->id);
-
-        $gauth = new google_authsub($token);
-        // revoke token from google
-        $gauth->revoke_session_token();
-
-        google_picasa::delete_sesskey($USER->id);
-        $this->subauthtoken = '';
-
+    public function logout() {
+        $this->googleoauth->log_out();
         return parent::logout();
     }
 
-    public function get_name(){
+    public function get_name() {
         return get_string('pluginname', 'repository_picasa');
     }
     public function supported_filetypes() {
@@ -133,7 +105,27 @@ class repository_picasa extends repository {
     public function supported_returntypes() {
         return (FILE_INTERNAL | FILE_EXTERNAL);
     }
+
+    public static function get_type_option_names() {
+        return array('clientid', 'secret', 'pluginname');
+    }
+
+    public static function type_config_form($mform, $classname = 'repository') {
+        $a = new stdClass;
+        $a->docsurl = get_docs_url('Google_OAuth2_Setup');
+        $a->callbackurl = google_oauth::callback_url()->out(false);
+
+        $mform->addElement('static', null, '', get_string('oauthinfo', 'repository_picasa', $a));
+
+        parent::type_config_form($mform);
+        $mform->addElement('text', 'clientid', get_string('clientid', 'repository_picasa'));
+        $mform->addElement('text', 'secret', get_string('secret', 'repository_picasa'));
+
+        $strrequired = get_string('required');
+        $mform->addRule('clientid', $strrequired, 'required', null, 'client');
+        $mform->addRule('secret', $strrequired, 'required', null, 'client');
+    }
 }
 
 // Icon for this plugin retrieved from http://www.iconspedia.com/icon/picasa-2711.html
-// Where the license is said documented to be Free
+// Where the license is said documented to be Free.
index 5ee9d18..471007a 100644 (file)
@@ -26,6 +26,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2011112900;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2011112900;        // Requires this Moodle version
-$plugin->component = 'repository_picasa'; // Full name of the plugin (used for diagnostics)
+$plugin->version   = 2012051400;        // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2012051100;        // Requires this Moodle version.
+$plugin->component = 'repository_picasa'; // Full name of the plugin (used for diagnostics).