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
/**
19
 * This file contains the class definition for the mahara portfolio plugin
20
 *
21
 * @since Moodle 2.0
22
 * @package moodlecore
23
 * @subpackage portfolio
24
 * @copyright 2009 Penny Leach
25
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26
 */
27
 
28
 
29
define('PORTFOLIO_MAHARA_ERR_NETWORKING_OFF', 'err_networkingoff');
30
define('PORTFOLIO_MAHARA_ERR_NOHOSTS', 'err_nomnethosts');
31
define('PORTFOLIO_MAHARA_ERR_INVALIDHOST', 'err_invalidhost');
32
define('PORTFOLIO_MAHARA_ERR_NOMNETAUTH', 'err_nomnetauth');
33
 
34
require_once($CFG->libdir . '/portfoliolib.php');
35
require_once($CFG->libdir . '/portfolio/plugin.php');
36
require_once($CFG->libdir . '/portfolio/exporter.php');
37
require_once($CFG->dirroot . '/mnet/lib.php');
38
 
39
define('PORTFOLIO_MAHARA_QUEUE', PORTFOLIO_TIME_HIGH);
40
define('PORTFOLIO_MAHARA_IMMEDIATE', PORTFOLIO_TIME_MODERATE);
41
 
42
class portfolio_plugin_mahara extends portfolio_plugin_pull_base {
43
 
44
    private $hosts; // used in the admin config form
45
    private $mnethost; // privately set during export from the admin config value (mnethostid)
46
    private $hostrecord; // the host record that corresponds to the peer
47
    private $token; // during-transfer token
48
    private $sendtype; // whatever mahara has said it can handle (immediate or queued)
49
    private $filesmanifest; // manifest of files to send to mahara (set during prepare_package and sent later)
50
    private $totalsize; // total size of all included files added together
51
    private $continueurl; // if we've been sent back a specific url to continue to (eg folder id)
52
 
53
    /** @var mnet_environment the equivalent of old $MNET global. */
54
    public $mnet;
55
 
56
    protected function init() {
57
        $this->mnet = get_mnet_environment();
58
    }
59
 
60
    public function __wakeup() {
61
        $this->mnet = get_mnet_environment();
62
    }
63
 
64
    public static function get_name() {
65
        return get_string('pluginname', 'portfolio_mahara');
66
    }
67
 
68
    public static function get_allowed_config() {
69
        return array('mnethostid', 'enableleap2a');
70
    }
71
 
72
    public function supported_formats() {
73
        if ($this->get_config('enableleap2a')) {
74
            return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_LEAP2A);
75
        }
76
        return array(PORTFOLIO_FORMAT_FILE);
77
    }
78
 
79
    public function expected_time($callertime) {
80
        if ($this->sendtype == PORTFOLIO_MAHARA_QUEUE) {
81
            return PORTFOLIO_TIME_FORCEQUEUE;
82
        }
83
        return $callertime;
84
    }
85
 
86
    public static function has_admin_config() {
87
        return true;
88
    }
89
 
90
    public static function admin_config_form(&$mform) {
91
        $strrequired = get_string('required');
92
        $hosts = self::get_mnet_hosts(); // this is called by sanity check but it's ok because it's cached
93
        foreach ($hosts as $host) {
94
            $hosts[$host->id] = $host->name;
95
        }
96
        $mform->addElement('select', 'mnethostid', get_string('mnethost', 'portfolio_mahara'), $hosts);
97
        $mform->addRule('mnethostid', $strrequired, 'required', null, 'client');
98
        $mform->setType('mnethostid', PARAM_INT);
99
        $mform->addElement('selectyesno', 'enableleap2a', get_string('enableleap2a', 'portfolio_mahara'));
100
        $mform->setType('enableleap2a', PARAM_BOOL);
101
    }
102
 
103
    public function instance_sanity_check() {
104
        // make sure the host record exists since we don't have referential integrity
105
        if (!is_enabled_auth('mnet')) {
106
            return PORTFOLIO_MAHARA_ERR_NOMNETAUTH;
107
        }
108
        try {
109
            $this->ensure_mnethost();
110
        }
111
        catch (portfolio_exception $e) {
112
            return PORTFOLIO_MAHARA_ERR_INVALIDHOST;
113
        }
114
        // make sure we have the right services
115
        $hosts = $this->get_mnet_hosts();
116
        if (!array_key_exists($this->get_config('mnethostid'), $hosts)) {
117
            return PORTFOLIO_MAHARA_ERR_INVALIDHOST;
118
        }
119
        return 0;
120
    }
121
 
122
    public static function plugin_sanity_check() {
123
        global $CFG, $DB;
124
        $errorcode = 0;
125
        if (!isset($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode != 'strict') {
126
            $errorcode =  PORTFOLIO_MAHARA_ERR_NETWORKING_OFF;
127
        }
128
        if (!is_enabled_auth('mnet')) {
129
            $errorcode = PORTFOLIO_MAHARA_ERR_NOMNETAUTH;
130
        }
131
        if (!self::get_mnet_hosts()) {
132
            $errorcode =  PORTFOLIO_MAHARA_ERR_NOHOSTS;
133
        }
134
        return $errorcode;
135
    }
136
 
137
    private static function get_mnet_hosts() {
138
        global $DB, $CFG;
139
        static $hosts;
140
        if (isset($hosts)) {
141
            return $hosts;
142
        }
143
        $hosts = $DB->get_records_sql('  SELECT
144
                                    h.id,
145
                                    h.wwwroot,
146
                                    h.ip_address,
147
                                    h.name,
148
                                    h.public_key,
149
                                    h.public_key_expires,
150
                                    h.transport,
151
                                    h.portno,
152
                                    h.last_connect_time,
153
                                    h.last_log_id,
154
                                    h.applicationid,
155
                                    a.name as app_name,
156
                                    a.display_name as app_display_name,
157
                                    a.xmlrpc_server_url
158
                                FROM {mnet_host} h
159
                                    JOIN {mnet_application} a ON h.applicationid=a.id
160
                                    JOIN {mnet_host2service} hs1 ON hs1.hostid = h.id
161
                                    JOIN {mnet_service} s1 ON hs1.serviceid = s1.id
162
                                    JOIN {mnet_host2service} hs2 ON hs2.hostid = h.id
163
                                    JOIN {mnet_service} s2 ON hs2.serviceid = s2.id
164
                                    JOIN {mnet_host2service} hs3 ON hs3.hostid = h.id
165
                                    JOIN {mnet_service} s3 ON hs3.serviceid = s3.id
166
                                WHERE
167
                                    h.id <> ? AND
168
                                    h.deleted = 0 AND
169
                                    a.name = ? AND
170
                                    s1.name = ? AND hs1.publish = ? AND
171
                                    s2.name = ? AND hs2.subscribe = ? AND
172
                                    s3.name = ? AND hs3.subscribe = ? AND
173
                                    s3.name = ? AND hs3.publish = ?',
174
                        array($CFG->mnet_localhost_id, 'mahara', 'sso_idp', 1, 'sso_sp', 1, 'pf', 1, 'pf', 1));
175
        return $hosts;
176
    }
177
 
178
    public function prepare_package() {
179
        $files = $this->exporter->get_tempfiles();
180
        $this->totalsize = 0;
181
        foreach ($files as $f) {
182
            $this->filesmanifest[$f->get_contenthash()] = array(
183
                'filename' => $f->get_filename(),
184
                'sha1'     => $f->get_contenthash(),
185
                'size'     => $f->get_filesize(),
186
            );
187
            $this->totalsize += $f->get_filesize();
188
        }
189
 
190
        $this->set('file', $this->exporter->zip_tempfiles());  // this will throw a file_exception which the exporter catches separately.
191
    }
192
 
193
    public function send_package() {
194
        global $CFG;
195
        // send the 'content_ready' request to mahara
196
        require_once($CFG->dirroot . '/mnet/xmlrpc/client.php');
197
        $client = new mnet_xmlrpc_client();
198
        $client->set_method('portfolio/mahara/lib.php/send_content_ready');
199
        $client->add_param($this->token);
200
        $client->add_param($this->get('user')->username);
201
        $client->add_param($this->resolve_format());
202
        $client->add_param(array(
203
            'filesmanifest' => $this->filesmanifest,
204
            'zipfilesha1'   => $this->get('file')->get_contenthash(),
205
            'zipfilesize'   => $this->get('file')->get_filesize(),
206
            'totalsize'     => $this->totalsize,
207
        ));
208
        $client->add_param($this->get_export_config('wait'));
209
        $this->ensure_mnethost();
210
        if (!$client->send($this->mnethost)) {
211
            foreach ($client->error as $errormessage) {
212
                list($code, $message) = array_map('trim',explode(':', $errormessage, 2));
213
                $message .= "ERROR $code:<br/>$errormessage<br/>";
214
            }
215
            throw new portfolio_export_exception($this->get('exporter'), 'failedtoping', 'portfolio_mahara', '', $message);
216
        }
217
        // we should get back...  an ok and a status
218
        // either we've been waiting a while and mahara has fetched the file or has queued it.
219
        $response = (object)$client->response;
220
        if (!$response->status) {
221
            throw new portfolio_export_exception($this->get('exporter'), 'failedtoping', 'portfolio_mahara');
222
        }
223
        if ($response->type =='queued') {
224
            $this->exporter->set_forcequeue();
225
        }
226
        if (isset($response->querystring)) {
227
            $this->continueurl = $response->querystring;
228
        }
229
        // if we're not queuing the logging might have already happened
230
        $this->exporter->update_log_url($this->get_static_continue_url());
231
    }
232
 
233
    public function get_static_continue_url() {
234
        $remoteurl = '';
235
        if ($this->resolve_format() == 'file') {
236
            $remoteurl = '/artefact/file/'; // we hopefully get the files that were imported highlighted
237
        }
238
        if (isset($this->continueurl)) {
239
            $remoteurl .= $this->continueurl;
240
        }
241
        return $remoteurl;
242
    }
243
 
244
    public function resolve_static_continue_url($remoteurl) {
245
        global $CFG;
246
        $this->ensure_mnethost();
247
        $u = new moodle_url('/auth/mnet/jump.php', array('hostid' => $this->get_config('mnethostid'), 'wantsurl' => $remoteurl));
248
        return $u->out();
249
    }
250
 
251
    public function get_interactive_continue_url() {
252
        return $this->resolve_static_continue_url($this->get_static_continue_url());
253
    }
254
 
255
    public function steal_control($stage) {
256
        if ($stage != PORTFOLIO_STAGE_CONFIG) {
257
            return false;
258
        }
259
        global $CFG;
260
        return $CFG->wwwroot . '/portfolio/mahara/preconfig.php?id=' . $this->exporter->get('id');
261
    }
262
 
263
    public function verify_file_request_params($params) {
264
        return false;
265
        // the data comes from an xmlrpc request,
266
        // not a request to file.php
267
    }
268
 
269
    /**
270
    * sends the 'content_intent' ping to mahara
271
    * if all goes well, this will set the 'token' and 'sendtype' member variables.
272
    */
273
    public function send_intent() {
274
        global $CFG, $DB;
275
        require_once($CFG->dirroot . '/mnet/xmlrpc/client.php');
276
        $client = new mnet_xmlrpc_client();
277
        $client->set_method('portfolio/mahara/lib.php/send_content_intent');
278
        $client->add_param($this->get('user')->username);
279
        $this->ensure_mnethost();
280
        if (!$client->send($this->mnethost)) {
281
            foreach ($client->error as $errormessage) {
282
                list($code, $message) = array_map('trim',explode(':', $errormessage, 2));
283
                $message .= "ERROR $code:<br/>$errormessage<br/>";
284
            }
285
            throw new portfolio_export_exception($this->get('exporter'), 'failedtoping', 'portfolio_mahara', '', $message);
286
        }
287
        // we should get back... the send type and a shared token
288
        $response = (object)$client->response;
289
        if (empty($response->sendtype) || empty($response->token)) {
290
            throw new portfolio_export_exception($this->get('exporter'), 'senddisallowed', 'portfolio_mahara');
291
        }
292
        switch ($response->sendtype) {
293
            case 'immediate':
294
                $this->sendtype = PORTFOLIO_MAHARA_IMMEDIATE;
295
                break;
296
            case 'queue':
297
                $this->sendtype = PORTFOLIO_MAHARA_QUEUE;
298
                break;
299
            case 'none':
300
            default:
301
                throw new portfolio_export_exception($this->get('exporter'), 'senddisallowed', 'portfolio_mahara');
302
        }
303
        $this->token = $response->token;
304
        $this->get('exporter')->save();
305
        // put the entry in the mahara queue table now too
306
        $q = new stdClass;
307
        $q->token = $this->token;
308
        $q->transferid = $this->get('exporter')->get('id');
309
        $DB->insert_record('portfolio_mahara_queue', $q);
310
    }
311
 
312
    private function ensure_mnethost() {
313
        if (!empty($this->hostrecord) && !empty($this->mnethost)) {
314
            return;
315
        }
316
        global $DB;
317
        if (!$this->hostrecord = $DB->get_record('mnet_host', array('id' => $this->get_config('mnethostid')))) {
318
            throw new portfolio_plugin_exception(PORTFOLIO_MAHARA_ERR_INVALIDHOST, 'portfolio_mahara');
319
        }
320
        $this->mnethost = new mnet_peer();
321
        $this->mnethost->set_wwwroot($this->hostrecord->wwwroot);
322
    }
323
 
324
    /**
325
    * xmlrpc (mnet) function to get the file.
326
    * reads in the file and returns it base_64 encoded
327
    * so that it can be enrypted by mnet.
328
    *
329
    * @param string $token the token recieved previously during send_content_intent
330
    */
331
    public static function fetch_file($token) {
332
        global $DB;
333
        $remoteclient = get_mnet_remote_client();
334
        try {
335
            if (!$transferid = $DB->get_field('portfolio_mahara_queue', 'transferid', array('token' => $token))) {
336
                throw new mnet_server_exception(8009, 'mnet_notoken', 'portfolio_mahara');
337
            }
338
            $exporter = portfolio_exporter::rewaken_object($transferid);
339
        } catch (portfolio_exception $e) {
340
            throw new mnet_server_exception(8010, 'mnet_noid', 'portfolio_mahara');
341
        }
342
        if ($exporter->get('instance')->get_config('mnethostid') != $remoteclient->id) {
343
            throw new mnet_server_exception(8011, 'mnet_wronghost', 'portfolio_mahara');
344
        }
345
        global $CFG;
346
        try {
347
            $i = $exporter->get('instance');
348
            $f = $i->get('file');
349
            if (empty($f) || !($f instanceof stored_file)) {
350
                throw new mnet_server_exception(8012, 'mnet_nofile', 'portfolio_mahara');
351
            }
352
            try {
353
                $c = $f->get_content();
354
            } catch (file_exception $e) {
355
                throw new mnet_server_exception(8013, 'mnet_nofilecontents', 'portfolio_mahara', $e->getMessage());
356
            }
357
            $contents = base64_encode($c);
358
        } catch (Exception $e) {
359
            throw new mnet_server_exception(8013, 'mnet_nofile', 'portfolio_mahara');
360
        }
361
        $exporter->log_transfer();
362
        $exporter->process_stage_cleanup(true);
363
        return $contents;
364
    }
365
 
366
    public function cleanup() {
367
        global $DB;
368
        $DB->delete_records('portfolio_mahara_queue', array('transferid' => $this->get('exporter')->get('id'), 'token' => $this->token));
369
    }
370
 
371
 
372
    /**
373
     * internal helper function, that converts between the format constant,
374
     * which might be too specific (eg 'image') and the class in our *supported* list
375
     * which might be higher up the format hierarchy tree (eg 'file')
376
     */
377
    private function resolve_format() {
378
        global $CFG;
379
        $thisformat = $this->get_export_config('format');
380
        $allformats = portfolio_supported_formats();
381
        require_once($CFG->libdir . '/portfolio/formats.php');
382
        $thisobj = new $allformats[$thisformat];
383
        foreach ($this->supported_formats() as $f) {
384
            $class = $allformats[$f];
385
            if ($thisobj instanceof $class) {
386
                return $f;
387
            }
388
        }
389
    }
390
}
391
 
392