Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 * Simple implementation of some Google API functions for Moodle.
19
 *
20
 * @package   core
21
 * @copyright Dan Poltawski <talktodan@gmail.com>
22
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
defined('MOODLE_INTERNAL') || die();
26
 
27
require_once($CFG->libdir.'/filelib.php');
28
require_once($CFG->libdir.'/oauthlib.php');
29
 
30
/**
31
 * Class for manipulating google documents through the google data api.
32
 *
33
 * Docs for this can be found here:
34
 * {@link http://code.google.com/apis/documents/docs/2.0/developers_guide_protocol.html}
35
 *
36
 * @package    core
37
 * @subpackage lib
38
 * @copyright Dan Poltawski <talktodan@gmail.com>
39
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40
 */
41
class google_docs {
42
    /** @var string Realm for authentication, need both docs and spreadsheet realm */
43
    const REALM            = 'https://docs.google.com/feeds/ https://spreadsheets.google.com/feeds/ https://docs.googleusercontent.com/';
44
    /** @var string Document list url */
45
    const DOCUMENTFEED_URL = 'https://docs.google.com/feeds/default/private/full';
46
    /** @var string Upload url */
47
    const UPLOAD_URL       = 'https://docs.google.com/feeds/upload/create-session/default/private/full?convert=false';
48
 
49
    /** @var google_oauth oauth curl class for making authenticated requests */
50
    private $googleoauth = null;
51
 
52
    /**
53
     * Constructor.
54
     *
55
     * @param google_oauth $googleoauth oauth curl class for making authenticated requests
56
     */
57
    public function __construct(google_oauth $googleoauth) {
58
        $this->googleoauth = $googleoauth;
59
        $this->reset_curl_state();
60
    }
61
 
62
    /**
63
     * Resets state on oauth curl object and set GData protocol
64
     * version
65
     */
66
    private function reset_curl_state() {
67
        $this->googleoauth->reset_state();
68
        $this->googleoauth->setHeader('GData-Version: 3.0');
69
    }
70
 
71
    /**
72
     * Returns a list of files the user has formated for files api
73
     *
74
     * @param string $search A search string to do full text search on the documents
75
     * @return mixed Array of files formated for fileapoi
76
     */
77
    public function get_file_list($search = '') {
78
        global $CFG, $OUTPUT;
79
        $url = self::DOCUMENTFEED_URL;
80
 
81
        if ($search) {
82
            $url.='?q='.urlencode($search);
83
        }
84
 
85
        $files = array();
86
        $content = $this->googleoauth->get($url);
87
        try {
88
            if (strpos($content, '<?xml') !== 0) {
89
                throw new moodle_exception('invalidxmlresponse');
90
            }
91
            $xml = new SimpleXMLElement($content);
92
        } catch (Exception $e) {
93
            // An error occured while trying to parse the XML, let's just return nothing. SimpleXML does not
94
            // return a more specific Exception, that's why the global Exception class is caught here.
95
            return $files;
96
        }
97
        date_default_timezone_set(core_date::get_user_timezone());
98
        foreach ($xml->entry as $gdoc) {
99
            $docid  = (string) $gdoc->children('http://schemas.google.com/g/2005')->resourceId;
100
            list($type, $docid) = explode(':', $docid);
101
 
102
            $title  = '';
103
            $source = '';
104
            // FIXME: We're making hard-coded choices about format here.
105
            // If the repo api can support it, we could let the user
106
            // chose.
107
            switch($type){
108
                case 'document':
109
                    $title = $gdoc->title.'.rtf';
110
                    $source = 'https://docs.google.com/feeds/download/documents/Export?id='.$docid.'&exportFormat=rtf';
111
                    break;
112
                case 'presentation':
113
                    $title = $gdoc->title.'.ppt';
114
                    $source = 'https://docs.google.com/feeds/download/presentations/Export?id='.$docid.'&exportFormat=ppt';
115
                    break;
116
                case 'spreadsheet':
117
                    $title = $gdoc->title.'.xls';
118
                    $source = 'https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key='.$docid.'&exportFormat=xls';
119
                    break;
120
                case 'pdf':
121
                case 'file':
122
                    $title  = (string)$gdoc->title;
123
                    // Some files don't have a content probably because the download has been restricted.
124
                    if (isset($gdoc->content)) {
125
                        $source = (string)$gdoc->content[0]->attributes()->src;
126
                    }
127
                    break;
128
            }
129
 
130
            $files[] =  array( 'title' => $title,
131
                'url' => "{$gdoc->link[0]->attributes()->href}",
132
                'source' => $source,
133
                'date'   => strtotime($gdoc->updated),
134
                'thumbnail' => (string) $OUTPUT->image_url(file_extension_icon($title))
135
            );
136
        }
137
        core_date::set_default_server_timezone();
138
 
139
        return $files;
140
    }
141
 
142
    /**
143
     * Sends a file object to google documents
144
     *
145
     * @param object $file File object
146
     * @return boolean True on success
147
     */
148
    public function send_file($file) {
149
        // First we create the 'resumable upload request'.
150
        $this->googleoauth->setHeader("Content-Length: 0");
151
        $this->googleoauth->setHeader("X-Upload-Content-Length: ". $file->get_filesize());
152
        $this->googleoauth->setHeader("X-Upload-Content-Type: ". $file->get_mimetype());
153
        $this->googleoauth->setHeader("Slug: ". $file->get_filename());
154
        $this->googleoauth->post(self::UPLOAD_URL);
155
 
156
        if ($this->googleoauth->info['http_code'] !== 200) {
157
            throw new moodle_exception('Cantpostupload');
158
        }
159
 
160
        // Now we http PUT the file in the location returned.
161
        $location = $this->googleoauth->response['Location'];
162
        if (empty($location)) {
163
            throw new moodle_exception('Nouploadlocation');
164
        }
165
 
166
        // Reset the curl object for actually sending the file.
167
        $this->reset_curl_state();
168
        $this->googleoauth->setHeader("Content-Length: ". $file->get_filesize());
169
        $this->googleoauth->setHeader("Content-Type: ". $file->get_mimetype());
170
 
171
        // We can't get a filepointer, so have to copy the file..
172
        $tmproot = make_temp_directory('googledocsuploads');
173
        $tmpfilepath = $tmproot.'/'.$file->get_contenthash();
174
        $file->copy_content_to($tmpfilepath);
175
 
176
        // HTTP PUT the file.
177
        $this->googleoauth->put($location, array('file'=>$tmpfilepath));
178
 
179
        // Remove the temporary file we created..
180
        unlink($tmpfilepath);
181
 
182
        if ($this->googleoauth->info['http_code'] === 201) {
183
            // Clear headers for further requests.
184
            $this->reset_curl_state();
185
            return true;
186
        } else {
187
            return false;
188
        }
189
    }
190
 
191
    /**
192
     * Downloads a file using authentication
193
     *
194
     * @param string $url url of file
195
     * @param string $path path to save file to
196
     * @param int $timeout request timeout, default 0 which means no timeout
197
     * @return array stucture for repository download_file
198
     */
199
    public function download_file($url, $path, $timeout = 0) {
200
        $result = $this->googleoauth->download_one($url, null, array('filepath' => $path, 'timeout' => $timeout));
201
        if ($result === true) {
202
            $info = $this->googleoauth->get_info();
203
            if (isset($info['http_code']) && $info['http_code'] == 200) {
204
                return array('path'=>$path, 'url'=>$url);
205
            } else {
206
                throw new moodle_exception('cannotdownload', 'repository');
207
            }
208
        } else {
209
            throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
210
        }
211
    }
212
}
213
 
214
/**
215
 * OAuth 2.0 client for Google Services
216
 *
217
 * @package   core
218
 * @copyright 2012 Dan Poltawski
219
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
220
 */
221
class google_oauth extends oauth2_client {
222
    /**
223
     * Returns the auth url for OAuth 2.0 request
224
     * @return string the auth url
225
     */
226
    protected function auth_url() {
227
        return 'https://accounts.google.com/o/oauth2/auth';
228
    }
229
 
230
    /**
231
     * Returns the token url for OAuth 2.0 request
232
     * @return string the auth url
233
     */
234
    protected function token_url() {
235
        return 'https://accounts.google.com/o/oauth2/token';
236
    }
237
 
238
    /**
239
     * Resets headers and response for multiple requests
240
     */
241
    public function reset_state() {
242
        $this->header = array();
243
        $this->response = array();
244
    }
245
 
246
    /**
247
     * Make a HTTP request, we override the parents because we do not
248
     * want to send accept headers (this was a change in the parent class and we want to keep the old behaviour).
249
     *
250
     * @param string $url The URL to request
251
     * @param array $options
252
     * @param mixed $acceptheader Not used.
253
     * @return string
254
     */
255
    protected function request($url, $options = array(), $acceptheader = 'application/json') {
256
        return parent::request($url, $options, false);
257
    }
258
}