MDL-15362 - localised mnet server fault strings and added size to send_content_ready
[moodle.git] / portfolio / type / mahara / lib.php
CommitLineData
254f2d05 1<?php
2
3define('PORTFOLIO_MAHARA_ERR_NETWORKING_OFF', 'err_networkingoff');
4define('PORTFOLIO_MAHARA_ERR_NOHOSTS', 'err_nomnethosts');
aae8cfdc 5define('PORTFOLIO_MAHARA_ERR_INVALIDHOST', 'err_invalidhost');
7254f56e 6define('PORTFOLIO_MAHARA_ERR_NOMNETAUTH', 'err_nomnetauth');
254f2d05 7
8require_once($CFG->dirroot . '/lib/portfoliolib.php');
9require_once($CFG->dirroot . '/mnet/lib.php');
10
11define('PORTFOLIO_MAHARA_QUEUE', PORTFOLIO_TIME_HIGH);
12define('PORTFOLIO_MAHARA_IMMEDIATE', PORTFOLIO_TIME_MODERATE);
13
14class portfolio_plugin_mahara extends portfolio_plugin_pull_base {
15
16 private $hosts; // used in the admin config form
17 private $mnethost; // privately set during export from the admin config value (mnethostid)
18 private $hostrecord; // the host record that corresponds to the peer
19 private $token; // during-transfer token
20 private $sendtype; // whatever mahara has said it can handle (immediate or queued)
21 private $filesmanifest; // manifest of files to send to mahara (set during prepare_package and sent later)
2f6bd2a9 22 private $totalsize; // total size of all included files added together
254f2d05 23
0f71f48b 24 public static function get_name() {
25 return get_string('pluginname', 'portfolio_mahara');
26 }
27
254f2d05 28 public static function get_allowed_config() {
29 return array('mnethostid');
30 }
31
32 public static function supported_formats() {
33 return array(PORTFOLIO_FORMAT_FILE);
34 }
35
36 public function expected_time($callertime) {
37 if ($this->sendtype == PORTFOLIO_MAHARA_QUEUE) {
38 return PORTFOLIO_TIME_FORCEQUEUE;
39 }
40 return $callertime;
41 }
42
43 public static function has_admin_config() {
44 return true;
45 }
46
47 public function admin_config_form(&$mform) {
254f2d05 48 $strrequired = get_string('required');
49 $hosts = self::get_mnet_hosts(); // this is called by sanity check but it's ok because it's cached
50 foreach ($hosts as $host) {
51 $hosts[$host->id] = $host->name;
52 }
53 $mform->addElement('select', 'mnethostid', get_string('mnethost', 'portfolio_mahara'), $hosts);
54 $mform->addRule('mnethostid', $strrequired, 'required', null, 'client');
55 }
56
aae8cfdc 57 public function instance_sanity_check() {
58 // make sure the host record exists since we don't have referential integrity
b0482154 59 if (!is_enabled_auth('mnet')) {
60 return PORTFOLIO_MAHARA_ERR_NOMNETAUTH;
61 }
aae8cfdc 62 try {
63 $this->ensure_mnethost();
64 }
65 catch (portfolio_exception $e) {
66 return PORTFOLIO_MAHARA_ERR_INVALIDHOST;
67 }
68 // make sure we have the right services
69 $hosts = $this->get_mnet_hosts();
70 if (!array_key_exists($this->get_config('mnethostid'), $hosts)) {
71 return PORTFOLIO_MAHARA_ERR_INVALIDHOST;
72 }
73 return 0;
74 }
254f2d05 75
76 public static function plugin_sanity_check() {
254f2d05 77 global $CFG, $DB;
78 $errorcode = 0;
79 if (!isset($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode != 'strict') {
80 $errorcode = PORTFOLIO_MAHARA_ERR_NETWORKING_OFF;
81 }
7254f56e 82 if (!is_enabled_auth('mnet')) {
83 $errorcode = PORTFOLIO_MAHARA_ERR_NOMNETAUTH;
84 }
254f2d05 85 if (!self::get_mnet_hosts()) {
86 $errorcode = PORTFOLIO_MAHARA_ERR_NOHOSTS;
87 }
254f2d05 88 return $errorcode;
89 }
90
91 private static function get_mnet_hosts() {
92 global $DB, $CFG;
93 static $hosts;
94 if (isset($this) && is_object($this) && isset($this->hosts)) {
95 return $this->hosts;
96 } else if (!isset($this) && isset($hosts)) {
97 return $hosts;
98 }
99 $hosts = $DB->get_records_sql(' SELECT
100 h.id,
101 h.wwwroot,
102 h.ip_address,
103 h.name,
104 h.public_key,
105 h.public_key_expires,
106 h.transport,
107 h.portno,
108 h.last_connect_time,
109 h.last_log_id,
110 h.applicationid,
111 a.name as app_name,
112 a.display_name as app_display_name,
113 a.xmlrpc_server_url
114 FROM {mnet_host} h
115 JOIN {mnet_application} a ON h.applicationid=a.id
116 JOIN {mnet_host2service} hs1 ON hs1.hostid = h.id
117 JOIN {mnet_service} s1 ON hs1.serviceid = s1.id
118 JOIN {mnet_host2service} hs2 ON hs2.hostid = h.id
119 JOIN {mnet_service} s2 ON hs2.serviceid = s2.id
120 JOIN {mnet_host2service} hs3 ON hs3.hostid = h.id
121 JOIN {mnet_service} s3 ON hs3.serviceid = s3.id
122 WHERE
123 h.id <> ? AND
124 h.deleted = 0 AND
125 a.name = ? AND
126 s1.name = ? AND hs1.publish = ? AND
127 s2.name = ? AND hs2.subscribe = ? AND
128 s3.name = ? AND hs3.subscribe = ?',
129 array($CFG->mnet_localhost_id, 'mahara', 'sso_idp', 1, 'sso_sp', 1, 'pf', 1));;
130 if (empty($hosts)) { $hosts = array(); }
131 if (isset($this) && is_object($this)) {
132 $this->hosts = $hosts;
133 }
134 return $hosts;
135 }
136
137 public function prepare_package() {
138 $files = $this->exporter->get_tempfiles();
2f6bd2a9 139 $this->totalsize = 0;
254f2d05 140 foreach ($files as $f) {
141 $this->filesmanifest[$f->get_contenthash()] = array(
142 'filename' => $f->get_filename(),
143 'sha1' => $f->get_contenthash(),
2f6bd2a9 144 'size' => $f->get_filesize(),
254f2d05 145 );
2f6bd2a9 146 $this->totalsize += $f->get_filesize();
254f2d05 147 }
148 $zipper = new zip_packer();
149
150 $filename = 'portfolio-export.zip';
151 if ($newfile = $zipper->archive_to_storage($files, SYSCONTEXTID, 'portfolio_exporter', $this->exporter->get('id'), '/final/', $filename, $this->user->id)) {
152 $this->set('file', $newfile);
153 return true;
154 }
155 return false;
156 }
157
aed2937f 158 private function ensure_environment() {
254f2d05 159 global $MNET;
160 if (empty($MNET)) {
161 $MNET = new mnet_environment();
162 $MNET->init();
163 } // no idea why this happens :(
aed2937f 164 }
165
166 public function send_package() {
167 global $CFG;
168 $this->ensure_environment();
254f2d05 169 // send the 'content_ready' request to mahara
170 require_once($CFG->dirroot . '/mnet/xmlrpc/client.php');
171 $client = new mnet_xmlrpc_client();
172 $client->set_method('portfolio/mahara/lib.php/send_content_ready');
173 $client->add_param($this->token);
174 $client->add_param($this->get('user')->username);
175 $client->add_param($this->resolve_format());
1c597211 176 $client->add_param(array(
177 'filesmanifest' => $this->filesmanifest,
2f6bd2a9 178 'zipfilesha1' => $this->get('file')->get_contenthash(),
179 'zipfilesize' => $this->get('file')->get_filesize(),
180 'totalsize' => $this->totalsize,
1c597211 181 ));
254f2d05 182 $client->add_param($this->get_export_config('wait'));
183 $this->ensure_mnethost();
184 if (!$client->send($this->mnethost)) {
185 foreach ($client->error as $errormessage) {
186 list($code, $message) = array_map('trim',explode(':', $errormessage, 2));
187 $message .= "ERROR $code:<br/>$errormessage<br/>";
188 }
189 throw new portfolio_export_exception($this->get('exporter'), 'failedtoping', 'portfolio_mahara', '', $message);
190 }
191 // we should get back... an ok and a status
192 // either we've been waiting a while and mahara has fetched the file or has queued it.
193 $response = (object)$client->response;
194 if (!$response->status) {
195 throw new portfolio_export_exception($this->get('exporter'), 'failedtoping', 'portfolio_mahara');
196 }
2f6bd2a9 197 // @todo penny we should check $response->type here, it will tell us 'queued' or 'complete'
198 // and we might want to tell the user if it's queued.
254f2d05 199 return true;
200 }
201
202 public function get_continue_url() {
203 $this->ensure_mnethost();
aed2937f 204 $this->ensure_environment();
205 $mnetauth = get_auth_plugin('mnet');
206 $remoteurl = '/artefact/file/';// @todo penny this might change later when we change formats.
207 if (!$url = $mnetauth->start_jump_session($this->get_config('mnethostid'), $remoteurl)) {
208 return false;
209 }
210 return $url;
254f2d05 211 }
212
213 public function steal_control($stage) {
214 if ($stage != PORTFOLIO_STAGE_CONFIG) {
215 return false;
216 }
217 global $CFG;
218 return $CFG->wwwroot . '/portfolio/type/mahara/preconfig.php?id=' . $this->exporter->get('id');
219 }
220
221 public function verify_file_request_params($params) {
222 return false;
223 // the data comes from an xmlrpc request,
224 // not a request to file.php
225 }
226
227 /**
228 * sends the 'content_intent' ping to mahara
229 * if all goes well, this will set the 'token' and 'sendtype' member variables.
230 */
231 public function send_intent() {
232 global $CFG, $DB;
233 require_once($CFG->dirroot . '/mnet/xmlrpc/client.php');
234 $client = new mnet_xmlrpc_client();
235 $client->set_method('portfolio/mahara/lib.php/send_content_intent');
236 $client->add_param($this->get('user')->username);
237 $this->ensure_mnethost();
238 if (!$client->send($this->mnethost)) {
239 foreach ($client->error as $errormessage) {
240 list($code, $message) = array_map('trim',explode(':', $errormessage, 2));
241 $message .= "ERROR $code:<br/>$errormessage<br/>";
242 }
243 throw new portfolio_export_exception($this->get('exporter'), 'failedtoping', 'portfolio_mahara', '', $message);
244 }
245 // we should get back... the send type and a shared token
246 $response = (object)$client->response;
247 if (empty($response->sendtype) || empty($response->token)) {
248 throw new portfolio_export_exception($this->get('exporter'), 'senddisallowed', 'portfolio_mahara');
249 }
250 switch ($response->sendtype) {
251 case 'immediate':
252 $this->sendtype = PORTFOLIO_MAHARA_IMMEDIATE;
253 break;
254 case 'queue':
255 $this->sendtype = PORTFOLIO_MAHARA_QUEUE;
256 break;
257 case 'none':
258 default:
259 throw new portfolio_export_exception($this->get('exporter'), 'senddisallowed', 'portfolio_mahara');
260 }
261 $this->token = $response->token;
262 $this->get('exporter')->save();
263 // put the entry in the mahara queue table now too
264 $q = new stdClass;
265 $q->token = $this->token;
266 $q->transferid = $this->get('exporter')->get('id');
267 $DB->insert_record('portfolio_mahara_queue', $q);
268 }
269
270 private function ensure_mnethost() {
271 if (!empty($this->hostrecord) && !empty($this->mnethost)) {
272 return;
273 }
274 global $DB;
aae8cfdc 275 if (!$this->hostrecord = $DB->get_record('mnet_host', array('id' => $this->get_config('mnethostid')))) {
276 throw new portfolio_plugin_exception(PORTFOLIO_MAHARA_ERR_INVALIDHOST, 'portfolio_mahara');
277 }
254f2d05 278 $this->mnethost = new mnet_peer();
279 $this->mnethost->set_wwwroot($this->hostrecord->wwwroot);
280 }
281
282 public static function mnet_publishes() {
283 $pf= array();
284 $pf['name'] = 'pf'; // Name & Description go in lang file
285 $pf['apiversion'] = 1;
286 $pf['methods'] = array('send_content_intent', 'send_content_ready', 'fetch_file');
287
288 return array($pf);
289 }
290
291 /**
292 * xmlrpc (mnet) function to get the file.
293 * reads in the file and returns it base_64 encoded
294 * so that it can be enrypted by mnet.
295 *
296 * @param string $token the token recieved previously during send_content_intent
297 */
298 public static function fetch_file($token) {
299 global $DB, $MNET_REMOTE_CLIENT;;
300 try {
aed2937f 301 if (!$transferid = $DB->get_field('portfolio_mahara_queue', 'transferid', array('token' => $token))) {
2f6bd2a9 302 exit(mnet_server_fault(8009, get_string('mnet_notoken', 'portfolio_mahara')));
aed2937f 303 }
254f2d05 304 $exporter = portfolio_exporter::rewaken_object($transferid);
305 } catch (portfolio_exception $e) {
2f6bd2a9 306 exit(mnet_server_fault(8010, get_string('mnet_noid', 'portfolio_mahara')));
254f2d05 307 }
308 if ($exporter->get('instance')->get_config('mnethostid') != $MNET_REMOTE_CLIENT->id) {
2f6bd2a9 309 exit(mnet_server_fault(8011, get_string('mnet_wronghost', 'portfolio_mahara')));
254f2d05 310 }
311 global $CFG;
d5dfe1b3 312 try {
313 $i = $exporter->get('instance');
314 $f = $i->get('file');
432ad8bf 315 if (empty($f) || !($f instanceof stored_file)) {
2f6bd2a9 316 exit(mnet_server_fault(8012, get_string('mnet_nofile', 'portfolio_mahara')));
d5dfe1b3 317 }
432ad8bf 318 try {
319 $c = $f->get_content();
320 } catch (file_exception $e) {
2f6bd2a9 321 exit(mnet_server_fault(8013, get_string('mnet_nofilecontents', 'portfolio_mahara', $e->getMessage())));
432ad8bf 322 }
d5dfe1b3 323 $contents = base64_encode($c);
324 } catch (Exception $e) {
2f6bd2a9 325 exit(mnet_server_fault(8013, get_string('mnet_nofile', 'portfolio_mahara')));
d5dfe1b3 326 }
254f2d05 327 $exporter->process_stage_cleanup(true);
328 return $contents;
329 }
330
331 public function cleanup() {
332 global $DB;
333 $DB->delete_records('portfolio_mahara_queue', array('transferid' => $this->get('exporter')->get('id'), 'token' => $this->token));
334 }
335
336
337 private function resolve_format() {
338 $thisformat = $this->get_export_config('format');
339 $allformats = portfolio_supported_formats();
340 $thisobj = new $allformats[$thisformat];
341 foreach ($this->supported_formats() as $f) {
342 $class = $allformats[$f];
343 if ($thisobj instanceof $class) {
344 return $f;
345 }
346 }
347 }
254f2d05 348}
349
350?>