|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00017 00029 define('PORTFOLIO_MAHARA_ERR_NETWORKING_OFF', 'err_networkingoff'); 00030 define('PORTFOLIO_MAHARA_ERR_NOHOSTS', 'err_nomnethosts'); 00031 define('PORTFOLIO_MAHARA_ERR_INVALIDHOST', 'err_invalidhost'); 00032 define('PORTFOLIO_MAHARA_ERR_NOMNETAUTH', 'err_nomnetauth'); 00033 00034 require_once($CFG->libdir . '/portfoliolib.php'); 00035 require_once($CFG->libdir . '/portfolio/plugin.php'); 00036 require_once($CFG->libdir . '/portfolio/exporter.php'); 00037 require_once($CFG->dirroot . '/mnet/lib.php'); 00038 00039 define('PORTFOLIO_MAHARA_QUEUE', PORTFOLIO_TIME_HIGH); 00040 define('PORTFOLIO_MAHARA_IMMEDIATE', PORTFOLIO_TIME_MODERATE); 00041 00042 class portfolio_plugin_mahara extends portfolio_plugin_pull_base { 00043 00044 private $hosts; // used in the admin config form 00045 private $mnethost; // privately set during export from the admin config value (mnethostid) 00046 private $hostrecord; // the host record that corresponds to the peer 00047 private $token; // during-transfer token 00048 private $sendtype; // whatever mahara has said it can handle (immediate or queued) 00049 private $filesmanifest; // manifest of files to send to mahara (set during prepare_package and sent later) 00050 private $totalsize; // total size of all included files added together 00051 private $continueurl; // if we've been sent back a specific url to continue to (eg folder id) 00052 00053 protected function init() { 00054 $this->mnet = get_mnet_environment(); 00055 } 00056 00057 public function __wakeup() { 00058 $this->mnet = get_mnet_environment(); 00059 } 00060 00061 public static function get_name() { 00062 return get_string('pluginname', 'portfolio_mahara'); 00063 } 00064 00065 public static function get_allowed_config() { 00066 return array('mnethostid', 'enableleap2a'); 00067 } 00068 00069 public function supported_formats() { 00070 if ($this->get_config('enableleap2a')) { 00071 return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_LEAP2A); 00072 } 00073 return array(PORTFOLIO_FORMAT_FILE); 00074 } 00075 00076 public function expected_time($callertime) { 00077 if ($this->sendtype == PORTFOLIO_MAHARA_QUEUE) { 00078 return PORTFOLIO_TIME_FORCEQUEUE; 00079 } 00080 return $callertime; 00081 } 00082 00083 public static function has_admin_config() { 00084 return true; 00085 } 00086 00087 public function admin_config_form(&$mform) { 00088 $strrequired = get_string('required'); 00089 $hosts = self::get_mnet_hosts(); // this is called by sanity check but it's ok because it's cached 00090 foreach ($hosts as $host) { 00091 $hosts[$host->id] = $host->name; 00092 } 00093 $mform->addElement('select', 'mnethostid', get_string('mnethost', 'portfolio_mahara'), $hosts); 00094 $mform->addRule('mnethostid', $strrequired, 'required', null, 'client'); 00095 $mform->addElement('selectyesno', 'enableleap2a', get_string('enableleap2a', 'portfolio_mahara')); 00096 } 00097 00098 public function instance_sanity_check() { 00099 // make sure the host record exists since we don't have referential integrity 00100 if (!is_enabled_auth('mnet')) { 00101 return PORTFOLIO_MAHARA_ERR_NOMNETAUTH; 00102 } 00103 try { 00104 $this->ensure_mnethost(); 00105 } 00106 catch (portfolio_exception $e) { 00107 return PORTFOLIO_MAHARA_ERR_INVALIDHOST; 00108 } 00109 // make sure we have the right services 00110 $hosts = $this->get_mnet_hosts(); 00111 if (!array_key_exists($this->get_config('mnethostid'), $hosts)) { 00112 return PORTFOLIO_MAHARA_ERR_INVALIDHOST; 00113 } 00114 return 0; 00115 } 00116 00117 public static function plugin_sanity_check() { 00118 global $CFG, $DB; 00119 $errorcode = 0; 00120 if (!isset($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode != 'strict') { 00121 $errorcode = PORTFOLIO_MAHARA_ERR_NETWORKING_OFF; 00122 } 00123 if (!is_enabled_auth('mnet')) { 00124 $errorcode = PORTFOLIO_MAHARA_ERR_NOMNETAUTH; 00125 } 00126 if (!self::get_mnet_hosts()) { 00127 $errorcode = PORTFOLIO_MAHARA_ERR_NOHOSTS; 00128 } 00129 return $errorcode; 00130 } 00131 00132 private static function get_mnet_hosts() { 00133 global $DB, $CFG; 00134 static $hosts; 00135 if (isset($hosts)) { 00136 return $hosts; 00137 } 00138 $hosts = $DB->get_records_sql(' SELECT 00139 h.id, 00140 h.wwwroot, 00141 h.ip_address, 00142 h.name, 00143 h.public_key, 00144 h.public_key_expires, 00145 h.transport, 00146 h.portno, 00147 h.last_connect_time, 00148 h.last_log_id, 00149 h.applicationid, 00150 a.name as app_name, 00151 a.display_name as app_display_name, 00152 a.xmlrpc_server_url 00153 FROM {mnet_host} h 00154 JOIN {mnet_application} a ON h.applicationid=a.id 00155 JOIN {mnet_host2service} hs1 ON hs1.hostid = h.id 00156 JOIN {mnet_service} s1 ON hs1.serviceid = s1.id 00157 JOIN {mnet_host2service} hs2 ON hs2.hostid = h.id 00158 JOIN {mnet_service} s2 ON hs2.serviceid = s2.id 00159 JOIN {mnet_host2service} hs3 ON hs3.hostid = h.id 00160 JOIN {mnet_service} s3 ON hs3.serviceid = s3.id 00161 WHERE 00162 h.id <> ? AND 00163 h.deleted = 0 AND 00164 a.name = ? AND 00165 s1.name = ? AND hs1.publish = ? AND 00166 s2.name = ? AND hs2.subscribe = ? AND 00167 s3.name = ? AND hs3.subscribe = ? AND 00168 s3.name = ? AND hs3.publish = ?', 00169 array($CFG->mnet_localhost_id, 'mahara', 'sso_idp', 1, 'sso_sp', 1, 'pf', 1, 'pf', 1)); 00170 return $hosts; 00171 } 00172 00173 public function prepare_package() { 00174 $files = $this->exporter->get_tempfiles(); 00175 $this->totalsize = 0; 00176 foreach ($files as $f) { 00177 $this->filesmanifest[$f->get_contenthash()] = array( 00178 'filename' => $f->get_filename(), 00179 'sha1' => $f->get_contenthash(), 00180 'size' => $f->get_filesize(), 00181 ); 00182 $this->totalsize += $f->get_filesize(); 00183 } 00184 00185 $this->set('file', $this->exporter->zip_tempfiles()); // this will throw a file_exception which the exporter catches separately. 00186 } 00187 00188 public function send_package() { 00189 global $CFG; 00190 // send the 'content_ready' request to mahara 00191 require_once($CFG->dirroot . '/mnet/xmlrpc/client.php'); 00192 $client = new mnet_xmlrpc_client(); 00193 $client->set_method('portfolio/mahara/lib.php/send_content_ready'); 00194 $client->add_param($this->token); 00195 $client->add_param($this->get('user')->username); 00196 $client->add_param($this->resolve_format()); 00197 $client->add_param(array( 00198 'filesmanifest' => $this->filesmanifest, 00199 'zipfilesha1' => $this->get('file')->get_contenthash(), 00200 'zipfilesize' => $this->get('file')->get_filesize(), 00201 'totalsize' => $this->totalsize, 00202 )); 00203 $client->add_param($this->get_export_config('wait')); 00204 $this->ensure_mnethost(); 00205 if (!$client->send($this->mnethost)) { 00206 foreach ($client->error as $errormessage) { 00207 list($code, $message) = array_map('trim',explode(':', $errormessage, 2)); 00208 $message .= "ERROR $code:<br/>$errormessage<br/>"; 00209 } 00210 throw new portfolio_export_exception($this->get('exporter'), 'failedtoping', 'portfolio_mahara', '', $message); 00211 } 00212 // we should get back... an ok and a status 00213 // either we've been waiting a while and mahara has fetched the file or has queued it. 00214 $response = (object)$client->response; 00215 if (!$response->status) { 00216 throw new portfolio_export_exception($this->get('exporter'), 'failedtoping', 'portfolio_mahara'); 00217 } 00218 if ($response->type =='queued') { 00219 $this->exporter->set_forcequeue(); 00220 } 00221 if (isset($response->querystring)) { 00222 $this->continueurl = $response->querystring; 00223 } 00224 // if we're not queuing the logging might have already happened 00225 $this->exporter->update_log_url($this->get_static_continue_url()); 00226 } 00227 00228 public function get_static_continue_url() { 00229 $remoteurl = ''; 00230 if ($this->resolve_format() == 'file') { 00231 $remoteurl = '/artefact/file/'; // we hopefully get the files that were imported highlighted 00232 } 00233 if (isset($this->continueurl)) { 00234 $remoteurl .= $this->continueurl; 00235 } 00236 return $remoteurl; 00237 } 00238 00239 public function resolve_static_continue_url($remoteurl) { 00240 global $CFG; 00241 $this->ensure_mnethost(); 00242 $u = new moodle_url('/auth/mnet/jump.php', array('hostid' => $this->get_config('mnethostid'), 'wantsurl' => $remoteurl)); 00243 return $u->out(); 00244 } 00245 00246 public function get_interactive_continue_url() { 00247 return $this->resolve_static_continue_url($this->get_static_continue_url()); 00248 } 00249 00250 public function steal_control($stage) { 00251 if ($stage != PORTFOLIO_STAGE_CONFIG) { 00252 return false; 00253 } 00254 global $CFG; 00255 return $CFG->wwwroot . '/portfolio/mahara/preconfig.php?id=' . $this->exporter->get('id'); 00256 } 00257 00258 public function verify_file_request_params($params) { 00259 return false; 00260 // the data comes from an xmlrpc request, 00261 // not a request to file.php 00262 } 00263 00268 public function send_intent() { 00269 global $CFG, $DB; 00270 require_once($CFG->dirroot . '/mnet/xmlrpc/client.php'); 00271 $client = new mnet_xmlrpc_client(); 00272 $client->set_method('portfolio/mahara/lib.php/send_content_intent'); 00273 $client->add_param($this->get('user')->username); 00274 $this->ensure_mnethost(); 00275 if (!$client->send($this->mnethost)) { 00276 foreach ($client->error as $errormessage) { 00277 list($code, $message) = array_map('trim',explode(':', $errormessage, 2)); 00278 $message .= "ERROR $code:<br/>$errormessage<br/>"; 00279 } 00280 throw new portfolio_export_exception($this->get('exporter'), 'failedtoping', 'portfolio_mahara', '', $message); 00281 } 00282 // we should get back... the send type and a shared token 00283 $response = (object)$client->response; 00284 if (empty($response->sendtype) || empty($response->token)) { 00285 throw new portfolio_export_exception($this->get('exporter'), 'senddisallowed', 'portfolio_mahara'); 00286 } 00287 switch ($response->sendtype) { 00288 case 'immediate': 00289 $this->sendtype = PORTFOLIO_MAHARA_IMMEDIATE; 00290 break; 00291 case 'queue': 00292 $this->sendtype = PORTFOLIO_MAHARA_QUEUE; 00293 break; 00294 case 'none': 00295 default: 00296 throw new portfolio_export_exception($this->get('exporter'), 'senddisallowed', 'portfolio_mahara'); 00297 } 00298 $this->token = $response->token; 00299 $this->get('exporter')->save(); 00300 // put the entry in the mahara queue table now too 00301 $q = new stdClass; 00302 $q->token = $this->token; 00303 $q->transferid = $this->get('exporter')->get('id'); 00304 $DB->insert_record('portfolio_mahara_queue', $q); 00305 } 00306 00307 private function ensure_mnethost() { 00308 if (!empty($this->hostrecord) && !empty($this->mnethost)) { 00309 return; 00310 } 00311 global $DB; 00312 if (!$this->hostrecord = $DB->get_record('mnet_host', array('id' => $this->get_config('mnethostid')))) { 00313 throw new portfolio_plugin_exception(PORTFOLIO_MAHARA_ERR_INVALIDHOST, 'portfolio_mahara'); 00314 } 00315 $this->mnethost = new mnet_peer(); 00316 $this->mnethost->set_wwwroot($this->hostrecord->wwwroot); 00317 } 00318 00326 public static function fetch_file($token) { 00327 global $DB; 00328 $remoteclient = get_mnet_remote_client(); 00329 try { 00330 if (!$transferid = $DB->get_field('portfolio_mahara_queue', 'transferid', array('token' => $token))) { 00331 throw new mnet_server_exception(8009, 'mnet_notoken', 'portfolio_mahara'); 00332 } 00333 $exporter = portfolio_exporter::rewaken_object($transferid); 00334 } catch (portfolio_exception $e) { 00335 throw new mnet_server_exception(8010, 'mnet_noid', 'portfolio_mahara'); 00336 } 00337 if ($exporter->get('instance')->get_config('mnethostid') != $remoteclient->id) { 00338 throw new mnet_server_exception(8011, 'mnet_wronghost', 'portfolio_mahara'); 00339 } 00340 global $CFG; 00341 try { 00342 $i = $exporter->get('instance'); 00343 $f = $i->get('file'); 00344 if (empty($f) || !($f instanceof stored_file)) { 00345 throw new mnet_server_exception(8012, 'mnet_nofile', 'portfolio_mahara'); 00346 } 00347 try { 00348 $c = $f->get_content(); 00349 } catch (file_exception $e) { 00350 throw new mnet_server_exception(8013, 'mnet_nofilecontents', 'portfolio_mahara', $e->getMessage()); 00351 } 00352 $contents = base64_encode($c); 00353 } catch (Exception $e) { 00354 throw new mnet_server_exception(8013, 'mnet_nofile', 'portfolio_mahara'); 00355 } 00356 $exporter->log_transfer(); 00357 $exporter->process_stage_cleanup(true); 00358 return $contents; 00359 } 00360 00361 public function cleanup() { 00362 global $DB; 00363 $DB->delete_records('portfolio_mahara_queue', array('transferid' => $this->get('exporter')->get('id'), 'token' => $this->token)); 00364 } 00365 00366 00372 private function resolve_format() { 00373 global $CFG; 00374 $thisformat = $this->get_export_config('format'); 00375 $allformats = portfolio_supported_formats(); 00376 require_once($CFG->libdir . '/portfolio/formats.php'); 00377 $thisobj = new $allformats[$thisformat]; 00378 foreach ($this->supported_formats() as $f) { 00379 $class = $allformats[$f]; 00380 if ($thisobj instanceof $class) { 00381 return $f; 00382 } 00383 } 00384 } 00385 } 00386 00387