From 6667f9e43935fcf183185cb9f1ef0daad9b6e164 Mon Sep 17 00:00:00 2001 From: poltawski Date: Sun, 8 Mar 2009 15:53:11 +0000 Subject: [PATCH] repository/googledocs New repository plugin MDL-16383 Google have now allowed documents to be downloaded via their API (http://googledataapis.blogspot.com/2009/02/start-downloads.html) so the google docs repo plugin could be finished. At the moment i've set the export format hardcoded, hopefully we can allow the repo api let the user choose later... --- lang/en_utf8/repository_googledocs.php | 3 + lib/googleapi.php | 53 ++++++++- repository/googledocs/icon.png | Bin 0 -> 4806 bytes repository/googledocs/repository.class.php | 127 +++++++++++++++++++++ 4 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 lang/en_utf8/repository_googledocs.php create mode 100644 repository/googledocs/icon.png create mode 100644 repository/googledocs/repository.class.php diff --git a/lang/en_utf8/repository_googledocs.php b/lang/en_utf8/repository_googledocs.php new file mode 100644 index 0000000000..e6bd104fca --- /dev/null +++ b/lang/en_utf8/repository_googledocs.php @@ -0,0 +1,3 @@ + diff --git a/lib/googleapi.php b/lib/googleapi.php index f945ce321d..e2bb069a31 100644 --- a/lib/googleapi.php +++ b/lib/googleapi.php @@ -52,6 +52,18 @@ abstract class google_auth_request extends curl{ 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.'"'); + } + + $ret = parent::multi($requests, $options); + // reset headers for next request + $this->header = array(); + return $ret; + } + public function get_sessiontoken(){ return $this->token; } @@ -190,7 +202,8 @@ class google_authsub extends google_auth_request { * http://code.google.com/apis/documents/docs/2.0/developers_guide_protocol.html */ class google_docs { - const REALM = 'http://docs.google.com/feeds/documents'; + // need both docs and the spreadsheets realm + const REALM = 'http://docs.google.com/feeds/ http://spreadsheets.google.com/feeds/'; const DOCUMENTFEED_URL = 'http://docs.google.com/feeds/documents/private/full'; const USER_PREF_NAME = 'google_authsub_sesskey'; @@ -229,6 +242,7 @@ class google_docs { */ #FIXME public function get_file_list($search = ''){ + global $CFG; $url = google_docs::DOCUMENTFEED_URL; if($search){ @@ -238,14 +252,41 @@ class google_docs { $xml = new SimpleXMLElement($content); + + $files = array(); foreach($xml->entry as $gdoc){ - $files[] = array( 'title' => "$gdoc->title", - 'url' => "{$gdoc->content['src']}", - 'source' => "{$gdoc->content['src']}", - 'date' => usertime(strtotime($gdoc->updated)), - ); + // there doesn't seem to to be cleaner way of getting the id/type + // than spliting this.. + if (preg_match('/^http:\/\/docs.google.com\/feeds\/documents\/private\/full\/([^%]*)%3A(.*)$/', $gdoc->id, $matches)){ + $docid = $matches[2]; + + // FIXME: We're making hard-coded choices about format here. + // If the repo api can support it, we could let the user + // chose. + switch($matches[1]){ + case 'document': + $title = $gdoc->title.'.rtf'; + $source = 'http://docs.google.com/feeds/download/documents/Export?docID='.$docid.'&exportFormat=rtf'; + break; + case 'presentation': + $title = $gdoc->title.'.ppt'; + $source = 'http://docs.google.com/feeds/download/presentations/Export?docID='.$docid.'&exportFormat=ppt'; + break; + case 'spreadsheet': + $title = $gdoc->title.'.xls'; + $source = 'http://spreadsheets.google.com/feeds/download/spreadsheets/Export?key='.$docid.'&fmcmd=4'; + break; + } + + $files[] = array( 'title' => $title, + 'url' => "{$gdoc->link[0]->attributes()->href}", + 'source' => $source, + 'date' => usertime(strtotime($gdoc->updated)), + 'thumbnail' => $CFG->pixpath.'/f/'.mimeinfo('icon32', $title) + ); + } } return $files; diff --git a/repository/googledocs/icon.png b/repository/googledocs/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cfefa4bbafd3e7d79fb0150bfcd5043ff8b937cf GIT binary patch literal 4806 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 literal 0 HcmV?d00001 diff --git a/repository/googledocs/repository.class.php b/repository/googledocs/repository.class.php new file mode 100644 index 0000000000..01803551b3 --- /dev/null +++ b/repository/googledocs/repository.class.php @@ -0,0 +1,127 @@ + + * @version $Id$ + * @license http://www.gnu.org/copyleft/gpl.html GNU Public License + */ + +require_once($CFG->libdir.'/googleapi.php'); + +class repository_googledocs extends repository { + private $subauthtoken = ''; + + public function __construct($repositoryid, $context = SITEID, $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); + } + + # fixme - we are not checking login before all functions in the repo api.. eg search + # MDL-17474 + $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; + } + + public function print_login($ajax = true){ + global $CFG; + if($ajax){ + $ret = array(); + $popup_btn = new stdclass; + $popup_btn->type = 'popup'; + $returnurl = $CFG->wwwroot.'/repository/ws.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 get_listing($path='', $page = '') { + $gdocs = new google_docs(new google_authsub($this->subauthtoken)); + + $ret = array(); + $ret['dynload'] = true; + $ret['list'] = $gdocs->get_file_list(); + return $ret; + } + + public function search($query){ + $gdocs = new google_docs(new google_authsub($this->subauthtoken)); + + $ret = array(); + $ret['dynload'] = true; + $ret['list'] = $gdocs->get_file_list($query); + 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 = ''; + + return parent::logout(); + } + + public function get_name(){ + return get_string('repositoryname', 'repository_googledocs'); + } + + public function get_file($url, $file) { + global $CFG; + + + //FIXME: Why does every repo plugin.. do this mktemp file itself.. + + if (!file_exists($CFG->dataroot.'/repository/download')) { + mkdir($CFG->dataroot.'/repository/download/', 0777, true); + } + + if(is_dir($CFG->dataroot.'/repository/download')) { + $dir = $CFG->dataroot.'/repository/download/'; + } + + if (empty($file)){ + $file = time(); + } + + $fp = fopen($dir.$file, 'w'); + $gdocs = new google_docs(new google_authsub($this->subauthtoken)); + $gdocs->download_file($url, $fp); + + return $dir.$file; + } + + +} +//Icon from: http://www.iconspedia.com/icon/google-2706.html -- 2.39.5