MDL-37984 portfolio: Google drive using official client library
[moodle.git] / portfolio / googledocs / lib.php
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/>.
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 require_once($CFG->libdir . '/google/Google/Service/Drive.php');
27 class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
28     /**
29      * Google Client.
30      * @var Google_Client
31      */
32     private $client = null;
34     /**
35      * Google Drive Service.
36      * @var Google_Service_Drive
37      */
38     private $service = null;
40     /**
41      * URL to redirect Google to.
42      * @var string
43      */
44     const REDIRECTURL = '/admin/oauth2callback.php';
45     /**
46      * Key in session which stores token (_drive_file is access level).
47      * @var string
48      */
49     const SESSIONKEY = 'googledrive_accesstoken_drive_file';
51     public function supported_formats() {
52         return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_RICHHTML);
53     }
55     public static function get_name() {
56         return get_string('pluginname', 'portfolio_googledocs');
57     }
59     public function prepare_package() {
60         // We send the files as they are, no prep required.
61         return true;
62     }
64     public function get_interactive_continue_url() {
65         return 'http://drive.google.com/';
66     }
68     public function expected_time($callertime) {
69         // We're forcing this to be run 'interactively' because the plugin
70         // does not support running in cron.
71         return PORTFOLIO_TIME_LOW;
72     }
74     public function send_package() {
75         if (!$this->client) {
76             throw new portfolio_plugin_exception('noauthtoken', 'portfolio_googledocs');
77         }
79         foreach ($this->exporter->get_tempfiles() as $file) {
80             try {
81                 // Create drivefile object and fill it with data.
82                 $drivefile = new Google_Service_Drive_DriveFile();
83                 $drivefile->setTitle($file->get_filename());
84                 $drivefile->setMimeType($file->get_mimetype());
86                 $filecontent = $file->get_content();
87                 $createdfile = $this->service->files->insert($drivefile,
88                                                             array('data' => $filecontent,
89                                                                   'mimeType' => $file->get_mimetype(),
90                                                                   'uploadType' => 'multipart'));
91             } catch ( Exception $e ) {
92                 throw new portfolio_plugin_exception('sendfailed', 'portfolio_gdocs', $file->get_filename());
93             }
94         }
95         return true;
96     }
97     /**
98      * Gets the access token from session and sets it to client.
99      *
100      * @return null|string null or token.
101      */
102     private function get_access_token() {
103         global $SESSION;
104         if (isset($SESSION->{self::SESSIONKEY}) && $SESSION->{self::SESSIONKEY}) {
105             $this->client->setAccessToken($SESSION->{self::SESSIONKEY});
106             return $SESSION->{self::SESSIONKEY};
107         }
108         return null;
109     }
110     /**
111      * Sets the access token to session
112      *
113      * @param string $token access token in json format
114      * @return
115      */
116     private function set_access_token($token) {
117         global $SESSION;
118         $SESSION->{self::SESSIONKEY} = $token;
119     }
121     public function steal_control($stage) {
122         global $CFG;
123         if ($stage != PORTFOLIO_STAGE_CONFIG) {
124             return false;
125         }
127         $this->initialize_oauth();
128         if ($this->get_access_token()) {
129             // Ensure that token is not expired.
130             if (!$this->client->isAccessTokenExpired()) {
131                 return false;
132             }
133         }
134         return $this->client->createAuthUrl();
136     }
138     public function post_control($stage, $params) {
139         if ($stage != PORTFOLIO_STAGE_CONFIG) {
140             return;
141         }
142         // Get the authentication code send by Google.
143         $code = isset($params['oauth2code']) ? $params['oauth2code'] : null;
144         // Try to authenticate (throws exception which is catched higher).
145         $this->client->authenticate($code);
146         // Make sure we accually have access token at this time
147         // ...and store it for further use.
148         if ($accesstoken = $this->client->getAccessToken()) {
149             $this->set_access_token($accesstoken);
150         } else {
151             throw new portfolio_plugin_exception('nosessiontoken', 'portfolio_gdocs');
152         }
153     }
155     public static function allows_multiple_instances() {
156         return false;
157     }
159     public static function has_admin_config() {
160         return true;
161     }
163     public static function get_allowed_config() {
164         return array('clientid', 'secret');
165     }
167     public static function admin_config_form(&$mform) {
168         $a = new stdClass;
169         $a->docsurl = get_docs_url('Google_OAuth_2.0_setup');
170         $a->callbackurl = (new moodle_url(self::REDIRECTURL))->out(false);
172         $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_googledocs', $a));
174         $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_googledocs'));
175         $mform->setType('clientid', PARAM_RAW_TRIMMED);
176         $mform->addElement('text', 'secret', get_string('secret', 'portfolio_googledocs'));
177         $mform->setType('secret', PARAM_RAW_TRIMMED);
179         $strrequired = get_string('required');
180         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
181         $mform->addRule('secret', $strrequired, 'required', null, 'client');
182     }
184     private function initialize_oauth() {
185         $redirecturi = new moodle_url(self::REDIRECTURL);
186         $returnurl = new moodle_url('/portfolio/add.php');
187         $returnurl->param('postcontrol', 1);
188         $returnurl->param('id', $this->exporter->get('id'));
189         $returnurl->param('sesskey', sesskey());
191         $clientid = $this->get_config('clientid');
192         $secret = $this->get_config('secret');
194         // Setup Google client.
195         $this->client = get_google_client();
196         $this->client->setClientId($clientid);
197         $this->client->setClientSecret($secret);
198         $this->client->setScopes(array(Google_Service_Drive::DRIVE_FILE));
199         $this->client->setRedirectUri($redirecturi->out(false));
200         // URL to be called when redirecting from authentication.
201         $this->client->setState($returnurl->out_as_local_url(false));
202         // Setup drive upload service.
203         $this->service = new Google_Service_Drive($this->client);
205     }
207     public function instance_sanity_check() {
208         $clientid = $this->get_config('clientid');
209         $secret = $this->get_config('secret');
211         // If there is no oauth config (e.g. plugins upgraded from < 2.3 then
212         // there will be no config and this plugin should be disabled.
213         if (empty($clientid) or empty($secret)) {
214             return 'nooauthcredentials';
215         }
216         return 0;
217     }