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 | */ |
67a87e7d | 25 | require_once(dirname(dirname(__FILE__)) . '/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 | |
c95a6095 PL |
36 | $dataid = optional_param('id', 0, PARAM_INT); // 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 | |
4c7a4ef9 | 38 | $cancel = optional_param('cancel', 0, PARAM_RAW); // user has cancelled the request |
c95a6095 PL |
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 | |
4c7a4ef9 | 41 | $instanceid = optional_param('instance', 0, PARAM_INT); // instanceof of configured portfolio plugin |
42 | $courseid = optional_param('course', 0, PARAM_INT); // 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 | $callbackfile = optional_param('callbackfile', null, PARAM_PATH); // callback file eg /mod/forum/lib.php - the location 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. | |
59dd457e | 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. |
3fad0df6 | 50 | $PAGE->set_context(get_system_context()); |
c95a6095 | 51 | $PAGE->set_url('/portfolio/add.php', array('id' => $dataid, 'sesskey' => sesskey())); |
f84a4349 | 52 | $PAGE->set_pagelayout('standard'); |
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. | |
c737eed8 | 155 | if (empty($callbackfile) || 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)) { | |
168 | if (!$value = optional_param($key, false, PARAM_NUMBER)) { | |
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 | } | |
4c7a4ef9 | 176 | // righto, now we have the callback args set up |
177 | // load up the caller file and class and tell it to set up all the data | |
178 | // it needs | |
67a87e7d | 179 | require_once($CFG->dirroot . $callbackfile); |
766d61cb | 180 | if (!class_exists($callbackclass) || !is_subclass_of($callbackclass, 'portfolio_caller_base')) { |
181 | throw new portfolio_caller_exception('callbackclassinvalid', 'portfolio'); | |
182 | } | |
67a87e7d | 183 | $caller = new $callbackclass($callbackargs); |
4dc67f1e | 184 | $caller->set('user', $USER); |
59dd457e PL |
185 | if ($formats = explode(',', $callerformats)) { |
186 | $caller->set_formats_from_button($formats); | |
187 | } | |
0d06b6fd | 188 | $caller->load_data(); |
4c7a4ef9 | 189 | // this must check capabilities and either throw an exception or return false. |
67a87e7d | 190 | if (!$caller->check_permissions()) { |
9f3ef223 | 191 | throw new portfolio_caller_exception('nopermissions', 'portfolio', $caller->get_return_url()); |
67a87e7d | 192 | } |
67a87e7d | 193 | |
f1d2641d | 194 | portfolio_export_pagesetup($PAGE, $caller); // this calls require_login($course) if it can.. |
67a87e7d | 195 | |
de6d81e6 | 196 | // finally! set up the exporter object with the portfolio instance, and caller information elements |
197 | $exporter = new portfolio_exporter($instance, $caller, $callbackfile); | |
4c7a4ef9 | 198 | |
199 | // set the export-specific variables, and save. | |
67a87e7d | 200 | $exporter->set('user', $USER); |
84a44985 | 201 | $exporter->save(); |
67a87e7d | 202 | } |
203 | ||
67a87e7d | 204 | if (!$exporter->get('instance')) { |
205 | // we've just arrived but have no instance | |
4c7a4ef9 | 206 | // in this case the exporter object and the caller object have been set up above |
207 | // so just make a little form to select the portfolio plugin instance, | |
208 | // which is the last thing to do before starting the export. | |
59dd457e PL |
209 | // |
210 | // first check to make sure there is actually a point | |
211 | $options = portfolio_instance_select( | |
212 | portfolio_instances(), | |
213 | $exporter->get('caller')->supported_formats(), | |
214 | get_class($exporter->get('caller')), | |
521a6ab0 | 215 | $exporter->get('caller')->get_mimetype(), |
59dd457e PL |
216 | 'instance', |
217 | true, | |
218 | true | |
219 | ); | |
220 | if (empty($options)) { | |
221 | throw new portfolio_export_exception($exporter, 'noavailableplugins', 'portfolio'); | |
222 | } else if (count($options) == 1) { | |
223 | // no point displaying a form, just redirect. | |
9b27ffa0 DP |
224 | $optionskeys = array_keys($options); |
225 | $instance = array_shift($optionskeys); | |
59dd457e PL |
226 | redirect($CFG->wwwroot . '/portfolio/add.php?id= ' . $exporter->get('id') . '&instance=' . $instance . '&sesskey=' . sesskey()); |
227 | } | |
24ba58ee PL |
228 | // be very selective about not including this unless we really need to |
229 | require_once($CFG->libdir . '/portfolio/forms.php'); | |
59dd457e | 230 | $mform = new portfolio_instance_select('', array('id' => $exporter->get('id'), 'caller' => $exporter->get('caller'), 'options' => $options)); |
6fdd8fa7 | 231 | if ($mform->is_cancelled()) { |
84a44985 | 232 | $exporter->cancel_request(); |
6fdd8fa7 | 233 | } else if ($fromform = $mform->get_data()){ |
84a44985 | 234 | redirect($CFG->wwwroot . '/portfolio/add.php?instance=' . $fromform->instance . '&id=' . $exporter->get('id')); |
6fdd8fa7 | 235 | exit; |
236 | } | |
237 | else { | |
11fbe3fc | 238 | $exporter->print_header(get_string('selectplugin', 'portfolio')); |
de2bd9df | 239 | echo $OUTPUT->box_start(); |
6fdd8fa7 | 240 | $mform->display(); |
de2bd9df | 241 | echo $OUTPUT->box_end(); |
e6e565ab | 242 | echo $OUTPUT->footer(); |
6fdd8fa7 | 243 | exit; |
67a87e7d | 244 | } |
67a87e7d | 245 | } |
246 | ||
4c7a4ef9 | 247 | // if we haven't been passed &stage= grab it from the exporter. |
248 | if (!$stage) { | |
ac6a5492 | 249 | $stage = $exporter->get('stage'); |
250 | } | |
251 | ||
d67bfc32 | 252 | // for places returning control to pass (rather than PORTFOLIO_STAGE_PACKAGE |
253 | // which is unstable if they can't get to the constant (eg external system) | |
4c7a4ef9 | 254 | $alreadystolen = false; |
255 | if ($postcontrol) { // the magic request variable plugins must pass on returning here | |
34035201 | 256 | try { |
4c7a4ef9 | 257 | // allow it to read whatever gets sent back in the request |
258 | // this is useful for plugins that redirect away and back again | |
259 | // adding a token to the end of the url, for example box.net | |
34035201 | 260 | $exporter->instance()->post_control($stage, array_merge($_GET, $_POST)); |
261 | } catch (portfolio_plugin_exception $e) { | |
262 | portfolio_export_rethrow_exception($exporter, $e); | |
263 | } | |
4c7a4ef9 | 264 | $alreadystolen = true; // remember this so we don't get caught in a steal control loop! |
d67bfc32 | 265 | } |
ac6a5492 | 266 | |
9f3ef223 | 267 | // actually do the work now.. |
67a87e7d | 268 | $exporter->process_stage($stage, $alreadystolen); |
269 | ||
4317f92f | 270 |