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