Commit | Line | Data |
---|---|---|
67a87e7d | 1 | <?php |
4c7a4ef9 | 2 | /** |
3 | * Moodle - Modular Object-Oriented Dynamic Learning Environment | |
4 | * http://moodle.org | |
5 | * Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com | |
6 | * | |
7 | * This program is free software: you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation, either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | * | |
20 | * @package moodle | |
21 | * @subpackage portfolio | |
22 | * @author Penny Leach <penny@catalyst.net.nz> | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL | |
24 | * @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com | |
25 | * | |
26 | * This file is the main controller to do with the portfolio export wizard. | |
27 | */ | |
67a87e7d | 28 | require_once(dirname(dirname(__FILE__)) . '/config.php'); |
a239f01e | 29 | |
90658eef | 30 | if (empty($CFG->enableportfolios)) { |
a239f01e | 31 | print_error('disabled', 'portfolio'); |
32 | } | |
33 | ||
67a87e7d | 34 | require_once($CFG->libdir . '/portfoliolib.php'); |
24ba58ee PL |
35 | require_once($CFG->libdir . '/portfolio/exporter.php'); |
36 | require_once($CFG->libdir . '/portfolio/caller.php'); | |
37 | require_once($CFG->libdir . '/portfolio/plugin.php'); | |
50128512 | 38 | |
c95a6095 PL |
39 | $dataid = optional_param('id', 0, PARAM_INT); // id of partially completed export. corresponds to a record in portfolio_tempdata |
40 | $type = optional_param('type', null, PARAM_SAFEDIR); // if we're returning from an external system (postcontrol) for a single-export only plugin | |
4c7a4ef9 | 41 | $cancel = optional_param('cancel', 0, PARAM_RAW); // user has cancelled the request |
c95a6095 PL |
42 | $cancelsure = optional_param('cancelsure', 0, PARAM_BOOL); // make sure they confirm first |
43 | $logreturn = optional_param('logreturn', 0, PARAM_BOOL); // when cancelling, we can also come from the log page, rather than the caller | |
4c7a4ef9 | 44 | $instanceid = optional_param('instance', 0, PARAM_INT); // instanceof of configured portfolio plugin |
45 | $courseid = optional_param('course', 0, PARAM_INT); // courseid the data being exported belongs to (caller object should provide this later) | |
46 | $stage = optional_param('stage', PORTFOLIO_STAGE_CONFIG, PARAM_INT); // stage of the export we're at (stored in the exporter) | |
47 | $postcontrol = optional_param('postcontrol', 0, PARAM_INT); // when returning from some bounce to an external system, this gets passed | |
48 | $callbackfile = optional_param('callbackfile', null, PARAM_PATH); // callback file eg /mod/forum/lib.php - the location of the exporting content | |
49 | $callbackclass = optional_param('callbackclass', null, PARAM_ALPHAEXT); // callback class eg forum_portfolio_caller - the class to handle the exporting content. | |
59dd457e | 50 | $callerformats = optional_param('callerformats', null, PARAM_TAGLIST); // comma separated list of formats the specific place exporting content supports |
50128512 | 51 | |
4c7a4ef9 | 52 | require_login(); // this is selectively called again with $course later when we know for sure which one we're in. |
3fad0df6 | 53 | $PAGE->set_context(get_system_context()); |
c95a6095 | 54 | $PAGE->set_url('/portfolio/add.php', array('id' => $dataid, 'sesskey' => sesskey())); |
f84a4349 | 55 | $PAGE->set_pagelayout('standard'); |
67a87e7d | 56 | $exporter = null; |
84a44985 | 57 | |
c95a6095 PL |
58 | if ($postcontrol && $type && !$dataid) { |
59 | // we're returning from an external system that can't construct dynamic return urls | |
60 | // this is a special "one export of this type only per session" case | |
61 | if (portfolio_static_function($type, 'allows_multiple_exports')) { | |
62 | throw new portfolio_exception('multiplesingleresume', 'portfolio'); | |
67a87e7d | 63 | } |
c95a6095 | 64 | |
b12fbe8e | 65 | if (!$dataid = portfolio_export_type_to_id($type, $USER->id)) { |
c95a6095 PL |
66 | throw new portfolio_exception('invalidtempid', 'portfolio'); |
67 | } | |
68 | } else { | |
69 | // we can't do this in the above case, because we're redirecting straight back from an external system | |
70 | // this is not really ideal, but since we're in a "staged" wizard, the session key is checked in other stages. | |
71 | require_sesskey(); // pretty much everything in this page is a write that could be hijacked, so just do this at the top here | |
84a44985 | 72 | } |
9f3ef223 | 73 | |
4c7a4ef9 | 74 | // if we have a dataid, it means we're in the middle of an export, |
75 | // so rewaken it and continue. | |
76 | if (!empty($dataid)) { | |
50128512 | 77 | try { |
78 | $exporter = portfolio_exporter::rewaken_object($dataid); | |
79 | } catch (portfolio_exception $e) { | |
9f3ef223 | 80 | // this can happen in some cases, a cancel request is sent when something is already broken |
81 | // so process it elegantly and move on. | |
50128512 | 82 | if ($cancel) { |
c95a6095 PL |
83 | if ($logreturn) { |
84 | redirect($CFG->wwwroot . '/user/portfoliologs.php'); | |
85 | } | |
50128512 | 86 | redirect($CFG->wwwroot); |
87 | } else { | |
c95a6095 | 88 | throw $e; |
50128512 | 89 | } |
90 | } | |
4c7a4ef9 | 91 | // we have to wake it up first before we can cancel it |
92 | // so temporary directories etc get cleaned up. | |
50128512 | 93 | if ($cancel) { |
c95a6095 PL |
94 | if ($cancelsure) { |
95 | $exporter->cancel_request($logreturn); | |
96 | } else { | |
34b9d4d4 | 97 | portfolio_export_pagesetup($PAGE, $exporter->get('caller')); |
11fbe3fc | 98 | $exporter->print_header(get_string('confirmcancel', 'portfolio')); |
c95a6095 | 99 | echo $OUTPUT->box_start(); |
67aec442 | 100 | $yesbutton = new single_button(new moodle_url('/portfolio/add.php', array('id' => $dataid, 'cancel' => 1, 'cancelsure' => 1, 'logreturn' => $logreturn)), get_string('yes')); |
59dd457e | 101 | if ($logreturn) { |
834ad953 | 102 | $nobutton = new single_button(new moodle_url('/user/portfoliologs.php'), get_string('no')); |
3ba60ee1 | 103 | } else { |
a6855934 | 104 | $nobutton = new single_button(new moodle_url('/portfolio/add.php', array('id' => $dataid)), get_string('no')); |
59dd457e PL |
105 | } |
106 | echo $OUTPUT->confirm(get_string('confirmcancel', 'portfolio'), $yesbutton, $nobutton); | |
c95a6095 PL |
107 | echo $OUTPUT->box_end(); |
108 | echo $OUTPUT->footer(); | |
109 | exit; | |
110 | } | |
67a87e7d | 111 | } |
c95a6095 | 112 | // verify we still belong to the correct user and permissions are still ok |
50128512 | 113 | $exporter->verify_rewaken(); |
4c7a4ef9 | 114 | // if we don't have an instanceid in the exporter |
115 | // it means we've just posted from the 'choose portfolio instance' page | |
116 | // so process that and start up the portfolio plugin | |
6fdd8fa7 | 117 | if (!$exporter->get('instance')) { |
4c7a4ef9 | 118 | if ($instanceid) { |
34035201 | 119 | try { |
4c7a4ef9 | 120 | $instance = portfolio_instance($instanceid); |
34035201 | 121 | } catch (portfolio_exception $e) { |
122 | portfolio_export_rethrow_exception($exporter, $e); | |
6fdd8fa7 | 123 | } |
4c7a4ef9 | 124 | // this technically shouldn't happen but make sure anyway |
6fdd8fa7 | 125 | if ($broken = portfolio_instance_sanity_check($instance)) { |
9f3ef223 | 126 | throw new portfolio_export_exception($exporter, $broken[$instance->get('id')], 'portfolio_' . $instance->get('plugin')); |
6fdd8fa7 | 127 | } |
4c7a4ef9 | 128 | // now we're all set up, ready to go |
6fdd8fa7 | 129 | $instance->set('user', $USER); |
130 | $exporter->set('instance', $instance); | |
d67bfc32 | 131 | $exporter->save(); |
6fdd8fa7 | 132 | } |
133 | } | |
f1d2641d PL |
134 | |
135 | portfolio_export_pagesetup($PAGE, $exporter->get('caller')); // this calls require_login($course) if it can.. | |
136 | ||
4c7a4ef9 | 137 | // completely new request, look to see what information we've been passed and set up the exporter object. |
67a87e7d | 138 | } else { |
4c7a4ef9 | 139 | // you cannot get here with no information for us, we must at least have the caller. |
c737eed8 | 140 | if (empty($_GET) && empty($_POST)) { |
141 | portfolio_exporter::print_expired_export(); | |
142 | } | |
67a87e7d | 143 | // we'e just posted here for the first time and have might the instance already |
4c7a4ef9 | 144 | if ($instanceid) { |
9f3ef223 | 145 | // this can throw exceptions but there's no point catching and rethrowing here |
146 | // as the exporter isn't created yet. | |
4c7a4ef9 | 147 | $instance = portfolio_instance($instanceid); |
67a87e7d | 148 | if ($broken = portfolio_instance_sanity_check($instance)) { |
34035201 | 149 | throw new portfolio_exception($broken[$instance->get('id')], 'portfolio_' . $instance->get('plugin')); |
67a87e7d | 150 | } |
151 | $instance->set('user', $USER); | |
152 | } else { | |
153 | $instance = null; | |
154 | } | |
155 | ||
4c7a4ef9 | 156 | // we must be passed this from the caller, we cannot start a new export |
157 | // without knowing information about what part of moodle we come from. | |
c737eed8 | 158 | if (empty($callbackfile) || empty($callbackclass)) { |
59dd457e | 159 | debugging('no callback file or class'); |
c737eed8 | 160 | portfolio_exporter::print_expired_export(); |
161 | } | |
67a87e7d | 162 | |
4c7a4ef9 | 163 | // so each place in moodle can pass callback args here |
164 | // process the entire request looking for ca_* | |
165 | // be as lenient as possible while still being secure | |
166 | // so only accept certain parameter types. | |
67a87e7d | 167 | $callbackargs = array(); |
9eb0a772 | 168 | foreach (array_keys(array_merge($_GET, $_POST)) as $key) { |
67a87e7d | 169 | if (strpos($key, 'ca_') === 0) { |
170 | if (!$value = optional_param($key, false, PARAM_ALPHAEXT)) { | |
171 | if (!$value = optional_param($key, false, PARAM_NUMBER)) { | |
172 | $value = optional_param($key, false, PARAM_PATH); | |
173 | } | |
174 | } | |
4c7a4ef9 | 175 | // strip off ca_ for niceness |
67a87e7d | 176 | $callbackargs[substr($key, 3)] = $value; |
177 | } | |
178 | } | |
4c7a4ef9 | 179 | // righto, now we have the callback args set up |
180 | // load up the caller file and class and tell it to set up all the data | |
181 | // it needs | |
67a87e7d | 182 | require_once($CFG->dirroot . $callbackfile); |
766d61cb | 183 | if (!class_exists($callbackclass) || !is_subclass_of($callbackclass, 'portfolio_caller_base')) { |
184 | throw new portfolio_caller_exception('callbackclassinvalid', 'portfolio'); | |
185 | } | |
67a87e7d | 186 | $caller = new $callbackclass($callbackargs); |
4dc67f1e | 187 | $caller->set('user', $USER); |
59dd457e PL |
188 | if ($formats = explode(',', $callerformats)) { |
189 | $caller->set_formats_from_button($formats); | |
190 | } | |
0d06b6fd | 191 | $caller->load_data(); |
4c7a4ef9 | 192 | // this must check capabilities and either throw an exception or return false. |
67a87e7d | 193 | if (!$caller->check_permissions()) { |
9f3ef223 | 194 | throw new portfolio_caller_exception('nopermissions', 'portfolio', $caller->get_return_url()); |
67a87e7d | 195 | } |
67a87e7d | 196 | |
f1d2641d | 197 | portfolio_export_pagesetup($PAGE, $caller); // this calls require_login($course) if it can.. |
67a87e7d | 198 | |
de6d81e6 | 199 | // finally! set up the exporter object with the portfolio instance, and caller information elements |
200 | $exporter = new portfolio_exporter($instance, $caller, $callbackfile); | |
4c7a4ef9 | 201 | |
202 | // set the export-specific variables, and save. | |
67a87e7d | 203 | $exporter->set('user', $USER); |
84a44985 | 204 | $exporter->save(); |
67a87e7d | 205 | } |
206 | ||
67a87e7d | 207 | if (!$exporter->get('instance')) { |
208 | // we've just arrived but have no instance | |
4c7a4ef9 | 209 | // in this case the exporter object and the caller object have been set up above |
210 | // so just make a little form to select the portfolio plugin instance, | |
211 | // which is the last thing to do before starting the export. | |
59dd457e PL |
212 | // |
213 | // first check to make sure there is actually a point | |
214 | $options = portfolio_instance_select( | |
215 | portfolio_instances(), | |
216 | $exporter->get('caller')->supported_formats(), | |
217 | get_class($exporter->get('caller')), | |
521a6ab0 | 218 | $exporter->get('caller')->get_mimetype(), |
59dd457e PL |
219 | 'instance', |
220 | true, | |
221 | true | |
222 | ); | |
223 | if (empty($options)) { | |
224 | throw new portfolio_export_exception($exporter, 'noavailableplugins', 'portfolio'); | |
225 | } else if (count($options) == 1) { | |
226 | // no point displaying a form, just redirect. | |
227 | $instance = array_shift(array_keys($options)); | |
228 | redirect($CFG->wwwroot . '/portfolio/add.php?id= ' . $exporter->get('id') . '&instance=' . $instance . '&sesskey=' . sesskey()); | |
229 | } | |
24ba58ee PL |
230 | // be very selective about not including this unless we really need to |
231 | require_once($CFG->libdir . '/portfolio/forms.php'); | |
59dd457e | 232 | $mform = new portfolio_instance_select('', array('id' => $exporter->get('id'), 'caller' => $exporter->get('caller'), 'options' => $options)); |
6fdd8fa7 | 233 | if ($mform->is_cancelled()) { |
84a44985 | 234 | $exporter->cancel_request(); |
6fdd8fa7 | 235 | } else if ($fromform = $mform->get_data()){ |
84a44985 | 236 | redirect($CFG->wwwroot . '/portfolio/add.php?instance=' . $fromform->instance . '&id=' . $exporter->get('id')); |
6fdd8fa7 | 237 | exit; |
238 | } | |
239 | else { | |
11fbe3fc | 240 | $exporter->print_header(get_string('selectplugin', 'portfolio')); |
de2bd9df | 241 | echo $OUTPUT->box_start(); |
6fdd8fa7 | 242 | $mform->display(); |
de2bd9df | 243 | echo $OUTPUT->box_end(); |
e6e565ab | 244 | echo $OUTPUT->footer(); |
6fdd8fa7 | 245 | exit; |
67a87e7d | 246 | } |
67a87e7d | 247 | } |
248 | ||
4c7a4ef9 | 249 | // if we haven't been passed &stage= grab it from the exporter. |
250 | if (!$stage) { | |
ac6a5492 | 251 | $stage = $exporter->get('stage'); |
252 | } | |
253 | ||
d67bfc32 | 254 | // for places returning control to pass (rather than PORTFOLIO_STAGE_PACKAGE |
255 | // which is unstable if they can't get to the constant (eg external system) | |
4c7a4ef9 | 256 | $alreadystolen = false; |
257 | if ($postcontrol) { // the magic request variable plugins must pass on returning here | |
34035201 | 258 | try { |
4c7a4ef9 | 259 | // allow it to read whatever gets sent back in the request |
260 | // this is useful for plugins that redirect away and back again | |
261 | // adding a token to the end of the url, for example box.net | |
34035201 | 262 | $exporter->instance()->post_control($stage, array_merge($_GET, $_POST)); |
263 | } catch (portfolio_plugin_exception $e) { | |
264 | portfolio_export_rethrow_exception($exporter, $e); | |
265 | } | |
4c7a4ef9 | 266 | $alreadystolen = true; // remember this so we don't get caught in a steal control loop! |
d67bfc32 | 267 | } |
ac6a5492 | 268 | |
9f3ef223 | 269 | // actually do the work now.. |
67a87e7d | 270 | $exporter->process_stage($stage, $alreadystolen); |
271 | ||
4317f92f | 272 |