MDL-37984 portfolio: Google drive using official client library
[moodle.git] / portfolio / googledocs / lib.php
CommitLineData
4317f92f 1<?php
4560fd1b
DP
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
ee91cf95 17/**
18 * Google Documents Portfolio Plugin
19 *
20 * @author Dan Poltawski <talktodan@gmail.com>
ee91cf95 21 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
22 */
f675815e 23require_once($CFG->libdir.'/portfolio/plugin.php');
8194541e
MM
24require_once($CFG->libdir . '/google/lib.php');
25require_once($CFG->libdir . '/google/Google/Service/Drive.php');
ee91cf95 26
27class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
8194541e
MM
28 /**
29 * Google Client.
30 * @var Google_Client
31 */
32 private $client = null;
33
34 /**
35 * Google Drive Service.
36 * @var Google_Service_Drive
37 */
38 private $service = null;
39
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';
ee91cf95 50
38652d90 51 public function supported_formats() {
4c291203 52 return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_RICHHTML);
ee91cf95 53 }
54
55 public static function get_name() {
56 return get_string('pluginname', 'portfolio_googledocs');
57 }
58
59 public function prepare_package() {
4560fd1b 60 // We send the files as they are, no prep required.
4317f92f 61 return true;
ee91cf95 62 }
4454447d 63
4560fd1b 64 public function get_interactive_continue_url() {
8194541e 65 return 'http://drive.google.com/';
ee91cf95 66 }
67
68 public function expected_time($callertime) {
bcf615af
DP
69 // We're forcing this to be run 'interactively' because the plugin
70 // does not support running in cron.
71 return PORTFOLIO_TIME_LOW;
ee91cf95 72 }
73
74 public function send_package() {
8194541e 75 if (!$this->client) {
4560fd1b 76 throw new portfolio_plugin_exception('noauthtoken', 'portfolio_googledocs');
ee91cf95 77 }
78
ee91cf95 79 foreach ($this->exporter->get_tempfiles() as $file) {
8194541e
MM
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());
85
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 ) {
ee91cf95 92 throw new portfolio_plugin_exception('sendfailed', 'portfolio_gdocs', $file->get_filename());
93 }
94 }
8194541e
MM
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;
ee91cf95 119 }
120
121 public function steal_control($stage) {
122 global $CFG;
123 if ($stage != PORTFOLIO_STAGE_CONFIG) {
124 return false;
125 }
126
4560fd1b 127 $this->initialize_oauth();
8194541e
MM
128 if ($this->get_access_token()) {
129 // Ensure that token is not expired.
130 if (!$this->client->isAccessTokenExpired()) {
131 return false;
132 }
ee91cf95 133 }
8194541e
MM
134 return $this->client->createAuthUrl();
135
ee91cf95 136 }
137
138 public function post_control($stage, $params) {
139 if ($stage != PORTFOLIO_STAGE_CONFIG) {
140 return;
141 }
8194541e
MM
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);
4560fd1b 150 } else {
8194541e 151 throw new portfolio_plugin_exception('nosessiontoken', 'portfolio_gdocs');
ee91cf95 152 }
ee91cf95 153 }
154
16f4918a
DP
155 public static function allows_multiple_instances() {
156 return false;
157 }
ee91cf95 158
4560fd1b
DP
159 public static function has_admin_config() {
160 return true;
161 }
162
163 public static function get_allowed_config() {
164 return array('clientid', 'secret');
165 }
166
c17ec774 167 public static function admin_config_form(&$mform) {
4560fd1b 168 $a = new stdClass;
8b503936 169 $a->docsurl = get_docs_url('Google_OAuth_2.0_setup');
8194541e 170 $a->callbackurl = (new moodle_url(self::REDIRECTURL))->out(false);
4560fd1b
DP
171
172 $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_googledocs', $a));
173
174 $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_googledocs'));
999427e9 175 $mform->setType('clientid', PARAM_RAW_TRIMMED);
4560fd1b 176 $mform->addElement('text', 'secret', get_string('secret', 'portfolio_googledocs'));
999427e9 177 $mform->setType('secret', PARAM_RAW_TRIMMED);
4560fd1b
DP
178
179 $strrequired = get_string('required');
180 $mform->addRule('clientid', $strrequired, 'required', null, 'client');
181 $mform->addRule('secret', $strrequired, 'required', null, 'client');
ee91cf95 182 }
183
4560fd1b 184 private function initialize_oauth() {
8194541e 185 $redirecturi = new moodle_url(self::REDIRECTURL);
4560fd1b
DP
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());
190
191 $clientid = $this->get_config('clientid');
192 $secret = $this->get_config('secret');
193
8194541e
MM
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);
204
4560fd1b 205 }
b7acfd64
DP
206
207 public function instance_sanity_check() {
208 $clientid = $this->get_config('clientid');
209 $secret = $this->get_config('secret');
210
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 }
ee91cf95 218}