Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 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 * Google Documents Portfolio Plugin 19 * 20 * @author Dan Poltawski <talktodan@gmail.com> 21 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 22 */ 23 require_once($CFG->libdir.'/portfolio/plugin.php'); 24 require_once($CFG->libdir . '/google/lib.php'); 25 26 class portfolio_plugin_googledocs extends portfolio_plugin_push_base { 27 /** 28 * Google Client. 29 * @var Google_Client 30 */ 31 private $client = null; 32 33 /** 34 * Google Drive Service. 35 * @var Google_Service_Drive 36 */ 37 private $service = null; 38 39 /** 40 * URL to redirect Google to. 41 * @var string 42 */ 43 const REDIRECTURL = '/admin/oauth2callback.php'; 44 /** 45 * Key in session which stores token (_drive_file is access level). 46 * @var string 47 */ 48 const SESSIONKEY = 'googledrive_accesstoken_drive_file'; 49 50 public function supported_formats() { 51 return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_RICHHTML); 52 } 53 54 public static function get_name() { 55 return get_string('pluginname', 'portfolio_googledocs'); 56 } 57 58 public function prepare_package() { 59 // We send the files as they are, no prep required. 60 return true; 61 } 62 63 public function get_interactive_continue_url() { 64 return 'http://drive.google.com/'; 65 } 66 67 public function expected_time($callertime) { 68 // We're forcing this to be run 'interactively' because the plugin 69 // does not support running in cron. 70 return PORTFOLIO_TIME_LOW; 71 } 72 73 public function send_package() { 74 if (!$this->client) { 75 throw new portfolio_plugin_exception('noauthtoken', 'portfolio_googledocs'); 76 } 77 78 // Create a parent directory for the export to Google Drive so that all files from the 79 // same export can be contained in one place for easy downloading. 80 $now = time(); 81 $exportdirectoryname = $this->exporter->get('caller')->display_name(); 82 $exportdirectoryname = strtolower(join('-', explode(' ', $exportdirectoryname))); 83 $exportdirectoryname = "/portfolio-export-{$exportdirectoryname}-{$now}"; 84 $directoryids = []; 85 86 foreach ($this->exporter->get_tempfiles() as $file) { 87 $filepath = $exportdirectoryname . $file->get_filepath(); 88 $directories = array_filter(explode('/', $filepath), function($part) { 89 return !empty($part); 90 }); 91 92 // Track how deep into the directory structure we are. This is the key 93 // we'll use to keep track of previously created directory ids. 94 $path = '/'; 95 // Track the parent directory so that we can look up it's id for creating 96 // subdirectories in Google Drive. 97 $parentpath = null; 98 99 // Create each of the directories in Google Drive that we need. 100 foreach ($directories as $directory) { 101 // Update the current path for this file. 102 $path .= "{$directory}/"; 103 104 if (!isset($directoryids[$path])) { 105 // This directory hasn't been created yet so let's go ahead and create it. 106 $parents = !is_null($parentpath) ? [$directoryids[$parentpath]] : []; 107 try { 108 $filemetadata = new Google_Service_Drive_DriveFile([ 109 'title' => $directory, 110 'mimeType' => 'application/vnd.google-apps.folder', 111 'parents' => $parents 112 ]); 113 114 $drivefile = $this->service->files->insert($filemetadata, ['fields' => 'id']); 115 $directoryids[$path] = ['id' => $drivefile->id]; 116 } catch (Exception $e) { 117 throw new portfolio_plugin_exception('sendfailed', 'portfolio_gdocs', $directory); 118 } 119 } 120 121 $parentpath = $path; 122 } 123 124 try { 125 // Create drivefile object and fill it with data. 126 $drivefile = new Google_Service_Drive_DriveFile(); 127 $drivefile->setTitle($file->get_filename()); 128 $drivefile->setMimeType($file->get_mimetype()); 129 // Add the parent directory id to make sure the file gets created in the correct 130 // directory in Google Drive. 131 $drivefile->setParents([$directoryids[$filepath]]); 132 133 $filecontent = $file->get_content(); 134 $this->service->files->insert($drivefile, 135 array('data' => $filecontent, 136 'mimeType' => $file->get_mimetype(), 137 'uploadType' => 'multipart')); 138 } catch ( Exception $e ) { 139 throw new portfolio_plugin_exception('sendfailed', 'portfolio_gdocs', $file->get_filename()); 140 } 141 } 142 return true; 143 } 144 /** 145 * Gets the access token from session and sets it to client. 146 * 147 * @return null|string null or token. 148 */ 149 private function get_access_token() { 150 global $SESSION; 151 if (isset($SESSION->{self::SESSIONKEY}) && $SESSION->{self::SESSIONKEY}) { 152 $this->client->setAccessToken($SESSION->{self::SESSIONKEY}); 153 return $SESSION->{self::SESSIONKEY}; 154 } 155 return null; 156 } 157 /** 158 * Sets the access token to session 159 * 160 * @param string $token access token in json format 161 * @return 162 */ 163 private function set_access_token($token) { 164 global $SESSION; 165 $SESSION->{self::SESSIONKEY} = $token; 166 } 167 168 public function steal_control($stage) { 169 global $CFG; 170 if ($stage != PORTFOLIO_STAGE_CONFIG) { 171 return false; 172 } 173 174 $this->initialize_oauth(); 175 if ($this->get_access_token()) { 176 // Ensure that token is not expired. 177 if (!$this->client->isAccessTokenExpired()) { 178 return false; 179 } 180 } 181 return $this->client->createAuthUrl(); 182 183 } 184 185 public function post_control($stage, $params) { 186 if ($stage != PORTFOLIO_STAGE_CONFIG) { 187 return; 188 } 189 // Get the authentication code send by Google. 190 $code = isset($params['oauth2code']) ? $params['oauth2code'] : null; 191 // Try to authenticate (throws exception which is catched higher). 192 $this->client->authenticate($code); 193 // Make sure we accually have access token at this time 194 // ...and store it for further use. 195 if ($accesstoken = $this->client->getAccessToken()) { 196 $this->set_access_token($accesstoken); 197 } else { 198 throw new portfolio_plugin_exception('nosessiontoken', 'portfolio_gdocs'); 199 } 200 } 201 202 public static function allows_multiple_instances() { 203 return false; 204 } 205 206 public static function has_admin_config() { 207 return true; 208 } 209 210 public static function get_allowed_config() { 211 return array('clientid', 'secret'); 212 } 213 214 public static function admin_config_form(&$mform) { 215 $a = new stdClass; 216 $a->docsurl = get_docs_url('Google_OAuth_2.0_setup'); 217 $a->callbackurl = (new moodle_url(self::REDIRECTURL))->out(false); 218 219 $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_googledocs', $a)); 220 221 $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_googledocs')); 222 $mform->setType('clientid', PARAM_RAW_TRIMMED); 223 $mform->addElement('text', 'secret', get_string('secret', 'portfolio_googledocs')); 224 $mform->setType('secret', PARAM_RAW_TRIMMED); 225 226 $strrequired = get_string('required'); 227 $mform->addRule('clientid', $strrequired, 'required', null, 'client'); 228 $mform->addRule('secret', $strrequired, 'required', null, 'client'); 229 } 230 231 private function initialize_oauth() { 232 $redirecturi = new moodle_url(self::REDIRECTURL); 233 $returnurl = new moodle_url('/portfolio/add.php'); 234 $returnurl->param('postcontrol', 1); 235 $returnurl->param('id', $this->exporter->get('id')); 236 $returnurl->param('sesskey', sesskey()); 237 238 $clientid = $this->get_config('clientid'); 239 $secret = $this->get_config('secret'); 240 241 // Setup Google client. 242 $this->client = get_google_client(); 243 $this->client->setClientId($clientid); 244 $this->client->setClientSecret($secret); 245 $this->client->setScopes(array(Google_Service_Drive::DRIVE_FILE)); 246 $this->client->setRedirectUri($redirecturi->out(false)); 247 // URL to be called when redirecting from authentication. 248 $this->client->setState($returnurl->out_as_local_url(false)); 249 // Setup drive upload service. 250 $this->service = new Google_Service_Drive($this->client); 251 252 } 253 254 public function instance_sanity_check() { 255 $clientid = $this->get_config('clientid'); 256 $secret = $this->get_config('secret'); 257 258 // If there is no oauth config (e.g. plugins upgraded from < 2.3 then 259 // there will be no config and this plugin should be disabled. 260 if (empty($clientid) or empty($secret)) { 261 return 'nooauthcredentials'; 262 } 263 return 0; 264 } 265 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body