Commit | Line | Data |
---|---|---|
32528f94 DS |
1 | <?php |
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 | ||
17 | /** | |
18 | * Library to handle drag and drop course uploads | |
19 | * | |
20 | * @package core | |
21 | * @subpackage lib | |
22 | * @copyright 2012 Davo smith | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
24 | */ | |
25 | ||
26 | defined('MOODLE_INTERNAL') || die(); | |
27 | ||
28 | require_once($CFG->dirroot.'/repository/lib.php'); | |
29 | require_once($CFG->dirroot.'/repository/upload/lib.php'); | |
30 | require_once($CFG->dirroot.'/course/lib.php'); | |
31 | ||
32 | /** | |
33 | * Add the Javascript to enable drag and drop upload to a course page | |
34 | * | |
35 | * @param object $course The currently displayed course | |
5103b5e6 DS |
36 | * @param array $modnames The list of enabled (visible) modules on this site |
37 | * @return void | |
32528f94 | 38 | */ |
5103b5e6 | 39 | function dndupload_add_to_course($course, $modnames) { |
32528f94 DS |
40 | global $CFG, $PAGE; |
41 | ||
3970a471 | 42 | $showstatus = optional_param('notifyeditingon', false, PARAM_BOOL); |
6c0ae99b | 43 | |
32528f94 | 44 | // Get all handlers. |
5103b5e6 DS |
45 | $handler = new dndupload_handler($course, $modnames); |
46 | $jsdata = $handler->get_js_data(); | |
47 | if (empty($jsdata->types) && empty($jsdata->filehandlers)) { | |
48 | return; // No valid handlers - don't enable drag and drop. | |
49 | } | |
32528f94 DS |
50 | |
51 | // Add the javascript to the page. | |
52 | $jsmodule = array( | |
33b24bdd | 53 | 'name' => 'coursedndupload', |
3f534371 | 54 | 'fullpath' => '/course/dndupload.js', |
32528f94 | 55 | 'strings' => array( |
33b24bdd | 56 | array('addfilehere', 'moodle'), |
b64300fc DS |
57 | array('dndworkingfiletextlink', 'moodle'), |
58 | array('dndworkingfilelink', 'moodle'), | |
59 | array('dndworkingfiletext', 'moodle'), | |
60 | array('dndworkingfile', 'moodle'), | |
61 | array('dndworkingtextlink', 'moodle'), | |
62 | array('dndworkingtext', 'moodle'), | |
63 | array('dndworkinglink', 'moodle'), | |
296af14b | 64 | array('namedfiletoolarge', 'moodle'), |
33b24bdd DS |
65 | array('actionchoice', 'moodle'), |
66 | array('servererror', 'moodle'), | |
4e737cf3 | 67 | array('filereaderror', 'moodle'), |
33b24bdd | 68 | array('upload', 'moodle'), |
0b245bf3 HN |
69 | array('cancel', 'moodle'), |
70 | array('changesmadereallygoaway', 'moodle') | |
32528f94 | 71 | ), |
66079e28 | 72 | 'requires' => array('node', 'event', 'json', 'anim') |
32528f94 DS |
73 | ); |
74 | $vars = array( | |
75 | array('courseid' => $course->id, | |
6afbdf27 | 76 | 'maxbytes' => get_user_max_upload_file_size($PAGE->context, $CFG->maxbytes, $course->maxbytes), |
6c0ae99b DS |
77 | 'handlers' => $handler->get_js_data(), |
78 | 'showstatus' => $showstatus) | |
32528f94 DS |
79 | ); |
80 | ||
81 | $PAGE->requires->js_init_call('M.course_dndupload.init', $vars, true, $jsmodule); | |
82 | } | |
83 | ||
84 | ||
85 | /** | |
86 | * Stores all the information about the available dndupload handlers | |
87 | * | |
88 | * @package core | |
89 | * @copyright 2012 Davo Smith | |
90 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
91 | */ | |
92 | class dndupload_handler { | |
93 | ||
94 | /** | |
95 | * @var array A list of all registered mime types that can be dropped onto a course | |
96 | * along with the modules that will handle them. | |
97 | */ | |
98 | protected $types = array(); | |
99 | ||
100 | /** | |
101 | * @var array A list of the different file types (extensions) that different modules | |
102 | * will handle. | |
103 | */ | |
104 | protected $filehandlers = array(); | |
105 | ||
e6a0f101 MG |
106 | /** |
107 | * @var context_course|null | |
108 | */ | |
109 | protected $context = null; | |
110 | ||
32528f94 DS |
111 | /** |
112 | * Gather a list of dndupload handlers from the different mods | |
113 | * | |
114 | * @param object $course The course this is being added to (to check course_allowed_module() ) | |
115 | */ | |
5103b5e6 | 116 | public function __construct($course, $modnames = null) { |
04348400 | 117 | global $CFG, $PAGE; |
32528f94 DS |
118 | |
119 | // Add some default types to handle. | |
120 | // Note: 'Files' type is hard-coded into the Javascript as this needs to be ... | |
121 | // ... treated a little differently. | |
1c14b1c1 | 122 | $this->register_type('url', array('url', 'text/uri-list', 'text/x-moz-url'), get_string('addlinkhere', 'moodle'), |
66079e28 | 123 | get_string('nameforlink', 'moodle'), get_string('whatforlink', 'moodle'), 10); |
1c14b1c1 | 124 | $this->register_type('text/html', array('text/html'), get_string('addpagehere', 'moodle'), |
66079e28 | 125 | get_string('nameforpage', 'moodle'), get_string('whatforpage', 'moodle'), 20); |
1c14b1c1 | 126 | $this->register_type('text', array('text', 'text/plain'), get_string('addpagehere', 'moodle'), |
66079e28 | 127 | get_string('nameforpage', 'moodle'), get_string('whatforpage', 'moodle'), 30); |
32528f94 | 128 | |
e6a0f101 MG |
129 | $this->context = context_course::instance($course->id); |
130 | ||
32528f94 | 131 | // Loop through all modules to find handlers. |
abed5d65 DS |
132 | $mods = get_plugin_list_with_function('mod', 'dndupload_register'); |
133 | foreach ($mods as $component => $funcname) { | |
56da374e | 134 | list($modtype, $modname) = core_component::normalize_component($component); |
5103b5e6 DS |
135 | if ($modnames && !array_key_exists($modname, $modnames)) { |
136 | continue; // Module is deactivated (hidden) at the site level. | |
137 | } | |
32528f94 | 138 | if (!course_allowed_module($course, $modname)) { |
5103b5e6 | 139 | continue; // User does not have permission to add this module to the course. |
32528f94 | 140 | } |
abed5d65 | 141 | $resp = $funcname(); |
32528f94 DS |
142 | if (!$resp) { |
143 | continue; | |
144 | } | |
145 | if (isset($resp['files'])) { | |
146 | foreach ($resp['files'] as $file) { | |
1c14b1c1 | 147 | $this->register_file_handler($file['extension'], $modname, $file['message']); |
32528f94 DS |
148 | } |
149 | } | |
150 | if (isset($resp['addtypes'])) { | |
151 | foreach ($resp['addtypes'] as $type) { | |
152 | if (isset($type['priority'])) { | |
153 | $priority = $type['priority']; | |
154 | } else { | |
155 | $priority = 100; | |
156 | } | |
66079e28 DS |
157 | if (!isset($type['handlermessage'])) { |
158 | $type['handlermessage'] = ''; | |
159 | } | |
1c14b1c1 | 160 | $this->register_type($type['identifier'], $type['datatransfertypes'], |
66079e28 | 161 | $type['addmessage'], $type['namemessage'], $type['handlermessage'], $priority); |
32528f94 DS |
162 | } |
163 | } | |
164 | if (isset($resp['types'])) { | |
165 | foreach ($resp['types'] as $type) { | |
2748d8ef | 166 | $noname = !empty($type['noname']); |
1c14b1c1 | 167 | $this->register_type_handler($type['identifier'], $modname, $type['message'], $noname); |
32528f94 DS |
168 | } |
169 | } | |
04348400 | 170 | $PAGE->requires->string_for_js('pluginname', $modname); |
32528f94 DS |
171 | } |
172 | } | |
173 | ||
174 | /** | |
175 | * Used to add a new mime type that can be drag and dropped onto a | |
176 | * course displayed in a browser window | |
177 | * | |
178 | * @param string $identifier The name that this type will be known as | |
179 | * @param array $datatransfertypes An array of the different types in the browser | |
180 | * 'dataTransfer.types' object that will map to this type | |
181 | * @param string $addmessage The message to display in the browser when this type is being | |
182 | * dragged onto the page | |
183 | * @param string $namemessage The message to pop up when asking for the name to give the | |
184 | * course module instance when it is created | |
66079e28 | 185 | * @param string $handlermessage The message to pop up when asking which module should handle this type |
32528f94 DS |
186 | * @param int $priority Controls the order in which types are checked by the browser (mainly |
187 | * needed to check for 'text' last as that is usually given as fallback) | |
188 | */ | |
1c14b1c1 | 189 | protected function register_type($identifier, $datatransfertypes, $addmessage, $namemessage, $handlermessage, $priority=100) { |
32528f94 DS |
190 | if ($this->is_known_type($identifier)) { |
191 | throw new coding_exception("Type $identifier is already registered"); | |
192 | } | |
193 | ||
194 | $add = new stdClass; | |
195 | $add->identifier = $identifier; | |
196 | $add->datatransfertypes = $datatransfertypes; | |
197 | $add->addmessage = $addmessage; | |
198 | $add->namemessage = $namemessage; | |
66079e28 | 199 | $add->handlermessage = $handlermessage; |
32528f94 DS |
200 | $add->priority = $priority; |
201 | $add->handlers = array(); | |
202 | ||
abed5d65 | 203 | $this->types[$identifier] = $add; |
32528f94 DS |
204 | } |
205 | ||
1c14b1c1 DW |
206 | /** |
207 | * Used to declare that a particular module will handle a particular type | |
208 | * of dropped data | |
209 | * | |
210 | * @param string $type The name of the type (as declared in register_type) | |
211 | * @param string $module The name of the module to handle this type | |
212 | * @param string $message The message to show the user if more than one handler is registered | |
213 | * for a type and the user needs to make a choice between them | |
214 | * @param bool $noname If true, the 'name' dialog should be disabled in the pop-up. | |
215 | * @throws coding_exception | |
216 | */ | |
217 | protected function register_type_handler($type, $module, $message, $noname) { | |
abed5d65 DS |
218 | if (!$this->is_known_type($type)) { |
219 | throw new coding_exception("Trying to add handler for unknown type $type"); | |
32528f94 DS |
220 | } |
221 | ||
abed5d65 DS |
222 | $add = new stdClass; |
223 | $add->type = $type; | |
224 | $add->module = $module; | |
225 | $add->message = $message; | |
2748d8ef | 226 | $add->noname = $noname ? 1 : 0; |
abed5d65 DS |
227 | |
228 | $this->types[$type]->handlers[] = $add; | |
32528f94 DS |
229 | } |
230 | ||
231 | /** | |
232 | * Used to declare that a particular module will handle a particular type | |
233 | * of dropped file | |
234 | * | |
235 | * @param string $extension The file extension to handle ('*' for all types) | |
236 | * @param string $module The name of the module to handle this type | |
237 | * @param string $message The message to show the user if more than one handler is registered | |
238 | * for a type and the user needs to make a choice between them | |
239 | */ | |
1c14b1c1 | 240 | protected function register_file_handler($extension, $module, $message) { |
abed5d65 DS |
241 | $extension = strtolower($extension); |
242 | ||
32528f94 DS |
243 | $add = new stdClass; |
244 | $add->extension = $extension; | |
245 | $add->module = $module; | |
246 | $add->message = $message; | |
247 | ||
248 | $this->filehandlers[] = $add; | |
249 | } | |
250 | ||
251 | /** | |
252 | * Check to see if the type has been registered | |
253 | * | |
254 | * @param string $type The identifier of the type you are interested in | |
255 | * @return bool True if the type is registered | |
256 | */ | |
257 | public function is_known_type($type) { | |
abed5d65 | 258 | return array_key_exists($type, $this->types); |
32528f94 DS |
259 | } |
260 | ||
261 | /** | |
262 | * Check to see if the module in question has registered to handle the | |
263 | * type given | |
264 | * | |
265 | * @param string $module The name of the module | |
266 | * @param string $type The identifier of the type | |
267 | * @return bool True if the module has registered to handle that type | |
268 | */ | |
269 | public function has_type_handler($module, $type) { | |
abed5d65 DS |
270 | if (!$this->is_known_type($type)) { |
271 | throw new coding_exception("Checking for handler for unknown type $type"); | |
272 | } | |
273 | foreach ($this->types[$type]->handlers as $handler) { | |
274 | if ($handler->module == $module) { | |
275 | return true; | |
32528f94 DS |
276 | } |
277 | } | |
278 | return false; | |
279 | } | |
280 | ||
281 | /** | |
282 | * Check to see if the module in question has registered to handle files | |
283 | * with the given extension (or to handle all file types) | |
284 | * | |
285 | * @param string $module The name of the module | |
286 | * @param string $extension The extension of the uploaded file | |
287 | * @return bool True if the module has registered to handle files with | |
288 | * that extension (or to handle all file types) | |
289 | */ | |
290 | public function has_file_handler($module, $extension) { | |
291 | foreach ($this->filehandlers as $handler) { | |
292 | if ($handler->module == $module) { | |
293 | if ($handler->extension == '*' || $handler->extension == $extension) { | |
294 | return true; | |
295 | } | |
296 | } | |
297 | } | |
298 | return false; | |
299 | } | |
300 | ||
301 | /** | |
302 | * Gets a list of the file types that are handled by a particular module | |
303 | * | |
304 | * @param string $module The name of the module to check | |
305 | * @return array of file extensions or string '*' | |
306 | */ | |
307 | public function get_handled_file_types($module) { | |
308 | $types = array(); | |
309 | foreach ($this->filehandlers as $handler) { | |
310 | if ($handler->module == $module) { | |
311 | if ($handler->extension == '*') { | |
312 | return '*'; | |
313 | } else { | |
314 | // Prepending '.' as otherwise mimeinfo fails. | |
315 | $types[] = '.'.$handler->extension; | |
316 | } | |
317 | } | |
318 | } | |
319 | return $types; | |
320 | } | |
321 | ||
322 | /** | |
323 | * Returns an object to pass onto the javascript code with data about all the | |
324 | * registered file / type handlers | |
325 | * | |
326 | * @return object Data to pass on to Javascript code | |
327 | */ | |
328 | public function get_js_data() { | |
f684250b DS |
329 | global $CFG; |
330 | ||
32528f94 DS |
331 | $ret = new stdClass; |
332 | ||
333 | // Sort the types by priority. | |
334 | uasort($this->types, array($this, 'type_compare')); | |
335 | ||
336 | $ret->types = array(); | |
1ddc3d1f | 337 | if (!empty($CFG->dndallowtextandlinks)) { |
f684250b DS |
338 | foreach ($this->types as $type) { |
339 | if (empty($type->handlers)) { | |
340 | continue; // Skip any types without registered handlers. | |
341 | } | |
342 | $ret->types[] = $type; | |
32528f94 | 343 | } |
32528f94 DS |
344 | } |
345 | ||
346 | $ret->filehandlers = $this->filehandlers; | |
e6a0f101 | 347 | $uploadrepo = repository::get_instances(array('type' => 'upload', 'currentcontext' => $this->context)); |
32528f94 DS |
348 | if (empty($uploadrepo)) { |
349 | $ret->filehandlers = array(); // No upload repo => no file handlers. | |
350 | } | |
351 | ||
352 | return $ret; | |
353 | } | |
354 | ||
355 | /** | |
356 | * Comparison function used when sorting types by priority | |
357 | * @param object $type1 first type to compare | |
358 | * @param object $type2 second type to compare | |
359 | * @return integer -1 for $type1 < $type2; 1 for $type1 > $type2; 0 for equal | |
360 | */ | |
361 | protected function type_compare($type1, $type2) { | |
362 | if ($type1->priority < $type2->priority) { | |
363 | return -1; | |
364 | } | |
365 | if ($type1->priority > $type2->priority) { | |
366 | return 1; | |
367 | } | |
368 | return 0; | |
369 | } | |
370 | ||
371 | } | |
372 | ||
373 | /** | |
374 | * Processes the upload, creating the course module and returning the result | |
375 | * | |
376 | * @package core | |
377 | * @copyright 2012 Davo Smith | |
378 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
379 | */ | |
abed5d65 | 380 | class dndupload_ajax_processor { |
32528f94 DS |
381 | |
382 | /** Returned when no error has occurred */ | |
383 | const ERROR_OK = 0; | |
384 | ||
385 | /** @var object The course that we are uploading to */ | |
386 | protected $course = null; | |
387 | ||
388 | /** @var context_course The course context for capability checking */ | |
389 | protected $context = null; | |
390 | ||
391 | /** @var int The section number we are uploading to */ | |
392 | protected $section = null; | |
393 | ||
394 | /** @var string The type of upload (e.g. 'Files', 'text/plain') */ | |
395 | protected $type = null; | |
396 | ||
397 | /** @var object The details of the module type that will be created */ | |
398 | protected $module= null; | |
399 | ||
400 | /** @var object The course module that has been created */ | |
401 | protected $cm = null; | |
402 | ||
403 | /** @var dndupload_handler used to check the allowed file types */ | |
404 | protected $dnduploadhandler = null; | |
405 | ||
406 | /** @var string The name to give the new activity instance */ | |
407 | protected $displayname = null; | |
408 | ||
409 | /** | |
410 | * Set up some basic information needed to handle the upload | |
411 | * | |
412 | * @param int $courseid The ID of the course we are uploading to | |
413 | * @param int $section The section number we are uploading to | |
414 | * @param string $type The type of upload (as reported by the browser) | |
415 | * @param string $modulename The name of the module requested to handle this upload | |
416 | */ | |
417 | public function __construct($courseid, $section, $type, $modulename) { | |
418 | global $DB; | |
419 | ||
abed5d65 DS |
420 | if (!defined('AJAX_SCRIPT')) { |
421 | throw new coding_exception('dndupload_ajax_processor should only be used within AJAX requests'); | |
422 | } | |
423 | ||
74df2951 | 424 | $this->course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); |
32528f94 DS |
425 | |
426 | require_login($this->course, false); | |
427 | $this->context = context_course::instance($this->course->id); | |
428 | ||
5103b5e6 | 429 | if (!is_number($section) || $section < 0) { |
32528f94 DS |
430 | throw new coding_exception("Invalid section number $section"); |
431 | } | |
432 | $this->section = $section; | |
433 | $this->type = $type; | |
434 | ||
435 | if (!$this->module = $DB->get_record('modules', array('name' => $modulename))) { | |
436 | throw new coding_exception("Module $modulename does not exist"); | |
437 | } | |
438 | ||
439 | $this->dnduploadhandler = new dndupload_handler($this->course); | |
440 | } | |
441 | ||
442 | /** | |
443 | * Check if this upload is a 'file' upload | |
444 | * | |
445 | * @return bool true if it is a 'file' upload, false otherwise | |
446 | */ | |
447 | protected function is_file_upload() { | |
448 | return ($this->type == 'Files'); | |
449 | } | |
450 | ||
451 | /** | |
452 | * Process the upload - creating the module in the course and returning the result to the browser | |
453 | * | |
454 | * @param string $displayname optional the name (from the browser) to give the course module instance | |
455 | * @param string $content optional the content of the upload (for non-file uploads) | |
456 | */ | |
457 | public function process($displayname = null, $content = null) { | |
458 | require_capability('moodle/course:manageactivities', $this->context); | |
459 | ||
460 | if ($this->is_file_upload()) { | |
461 | require_capability('moodle/course:managefiles', $this->context); | |
abed5d65 | 462 | if ($content != null) { |
33b24bdd | 463 | throw new moodle_exception('fileuploadwithcontent', 'moodle'); |
abed5d65 | 464 | } |
f684250b DS |
465 | } else { |
466 | if (empty($content)) { | |
467 | throw new moodle_exception('dnduploadwithoutcontent', 'moodle'); | |
468 | } | |
32528f94 DS |
469 | } |
470 | ||
471 | require_sesskey(); | |
472 | ||
473 | $this->displayname = $displayname; | |
474 | ||
475 | if ($this->is_file_upload()) { | |
476 | $this->handle_file_upload(); | |
477 | } else { | |
478 | $this->handle_other_upload($content); | |
479 | } | |
480 | } | |
481 | ||
482 | /** | |
483 | * Handle uploads containing files - create the course module, ask the upload repository | |
484 | * to process the file, ask the mod to set itself up, then return the result to the browser | |
485 | */ | |
486 | protected function handle_file_upload() { | |
487 | global $CFG; | |
488 | ||
489 | // Add the file to a draft file area. | |
490 | $draftitemid = file_get_unused_draft_itemid(); | |
6afbdf27 | 491 | $maxbytes = get_user_max_upload_file_size($this->context, $CFG->maxbytes, $this->course->maxbytes); |
32528f94 | 492 | $types = $this->dnduploadhandler->get_handled_file_types($this->module->name); |
a80f5922 | 493 | $repo = repository::get_instances(array('type' => 'upload', 'currentcontext' => $this->context)); |
32528f94 | 494 | if (empty($repo)) { |
33b24bdd | 495 | throw new moodle_exception('errornouploadrepo', 'moodle'); |
32528f94 DS |
496 | } |
497 | $repo = reset($repo); // Get the first (and only) upload repo. | |
498 | $details = $repo->process_upload(null, $maxbytes, $types, '/', $draftitemid); | |
499 | if (empty($this->displayname)) { | |
500 | $this->displayname = $this->display_name_from_file($details['file']); | |
501 | } | |
502 | ||
503 | // Create a course module to hold the new instance. | |
504 | $this->create_course_module(); | |
505 | ||
506 | // Ask the module to set itself up. | |
507 | $moduledata = $this->prepare_module_data($draftitemid); | |
508 | $instanceid = plugin_callback('mod', $this->module->name, 'dndupload', 'handle', array($moduledata), 'invalidfunction'); | |
509 | if ($instanceid === 'invalidfunction') { | |
510 | throw new coding_exception("{$this->module->name} does not support drag and drop upload (missing {$this->module->name}_dndupload_handle function"); | |
511 | } | |
512 | ||
513 | // Finish setting up the course module. | |
514 | $this->finish_setup_course_module($instanceid); | |
515 | } | |
516 | ||
517 | /** | |
518 | * Handle uploads not containing file - create the course module, ask the mod to | |
519 | * set itself up, then return the result to the browser | |
520 | * | |
521 | * @param string $content the content uploaded to the browser | |
522 | */ | |
523 | protected function handle_other_upload($content) { | |
abed5d65 DS |
524 | // Check this plugin is registered to handle this type of upload |
525 | if (!$this->dnduploadhandler->has_type_handler($this->module->name, $this->type)) { | |
526 | $info = (object)array('modname' => $this->module->name, 'type' => $this->type); | |
33b24bdd | 527 | throw new moodle_exception('moddoesnotsupporttype', 'moodle', $info); |
abed5d65 DS |
528 | } |
529 | ||
32528f94 DS |
530 | // Create a course module to hold the new instance. |
531 | $this->create_course_module(); | |
532 | ||
533 | // Ask the module to set itself up. | |
534 | $moduledata = $this->prepare_module_data(null, $content); | |
535 | $instanceid = plugin_callback('mod', $this->module->name, 'dndupload', 'handle', array($moduledata), 'invalidfunction'); | |
536 | if ($instanceid === 'invalidfunction') { | |
537 | throw new coding_exception("{$this->module->name} does not support drag and drop upload (missing {$this->module->name}_dndupload_handle function"); | |
538 | } | |
539 | ||
540 | // Finish setting up the course module. | |
541 | $this->finish_setup_course_module($instanceid); | |
542 | } | |
543 | ||
544 | /** | |
545 | * Generate the name of the mod instance from the name of the file | |
546 | * (remove the extension and convert underscore => space | |
547 | * | |
548 | * @param string $filename the filename of the uploaded file | |
549 | * @return string the display name to use | |
550 | */ | |
551 | protected function display_name_from_file($filename) { | |
2f1e464a | 552 | $pos = core_text::strrpos($filename, '.'); |
32528f94 | 553 | if ($pos) { // Want to skip if $pos === 0 OR $pos === false. |
2f1e464a | 554 | $filename = core_text::substr($filename, 0, $pos); |
32528f94 DS |
555 | } |
556 | return str_replace('_', ' ', $filename); | |
557 | } | |
558 | ||
559 | /** | |
560 | * Create the coursemodule to hold the file/content that has been uploaded | |
561 | */ | |
562 | protected function create_course_module() { | |
ac1a2975 | 563 | global $CFG; |
7f53e8aa | 564 | require_once($CFG->dirroot.'/course/modlib.php'); |
b17ee682 | 565 | list($module, $context, $cw, $cm, $data) = prepare_new_moduleinfo_data($this->course, $this->module->name, $this->section); |
ac1a2975 | 566 | |
7f53e8aa MG |
567 | $data->coursemodule = $data->id = add_course_module($data); |
568 | $this->cm = $data; | |
32528f94 DS |
569 | } |
570 | ||
571 | /** | |
572 | * Gather together all the details to pass on to the mod, so that it can initialise it's | |
573 | * own database tables | |
574 | * | |
575 | * @param int $draftitemid optional the id of the draft area containing the file (for file uploads) | |
576 | * @param string $content optional the content dropped onto the course (for non-file uploads) | |
577 | * @return object data to pass on to the mod, containing: | |
578 | * string $type the 'type' as registered with dndupload_handler (or 'Files') | |
579 | * object $course the course the upload was for | |
580 | * int $draftitemid optional the id of the draft area containing the files | |
581 | * int $coursemodule id of the course module that has already been created | |
582 | * string $displayname the name to use for this activity (can be overriden by the mod) | |
583 | */ | |
584 | protected function prepare_module_data($draftitemid = null, $content = null) { | |
585 | $data = new stdClass(); | |
586 | $data->type = $this->type; | |
587 | $data->course = $this->course; | |
588 | if ($draftitemid) { | |
589 | $data->draftitemid = $draftitemid; | |
590 | } else if ($content) { | |
591 | $data->content = $content; | |
592 | } | |
593 | $data->coursemodule = $this->cm->id; | |
594 | $data->displayname = $this->displayname; | |
595 | return $data; | |
596 | } | |
597 | ||
598 | /** | |
599 | * Called after the mod has set itself up, to finish off any course module settings | |
600 | * (set instance id, add to correct section, set visibility, etc.) and send the response | |
601 | * | |
602 | * @param int $instanceid id returned by the mod when it was created | |
603 | */ | |
604 | protected function finish_setup_course_module($instanceid) { | |
605 | global $DB, $USER; | |
606 | ||
607 | if (!$instanceid) { | |
608 | // Something has gone wrong - undo everything we can. | |
a347aee3 | 609 | course_delete_module($this->cm->id); |
33b24bdd | 610 | throw new moodle_exception('errorcreatingactivity', 'moodle', '', $this->module->name); |
32528f94 DS |
611 | } |
612 | ||
0470a094 DS |
613 | // Note the section visibility |
614 | $visible = get_fast_modinfo($this->course)->get_section_info($this->section)->visible; | |
615 | ||
32528f94 | 616 | $DB->set_field('course_modules', 'instance', $instanceid, array('id' => $this->cm->id)); |
38b19bbc MG |
617 | // Rebuild the course cache after update action |
618 | rebuild_course_cache($this->course->id, true); | |
32528f94 | 619 | |
722e6ba9 | 620 | $sectionid = course_add_cm_to_section($this->course, $this->cm->id, $this->section); |
32528f94 | 621 | |
0470a094 DS |
622 | set_coursemodule_visible($this->cm->id, $visible); |
623 | if (!$visible) { | |
624 | $DB->set_field('course_modules', 'visibleold', 1, array('id' => $this->cm->id)); | |
625 | } | |
32528f94 | 626 | |
38b19bbc | 627 | // retrieve the final info about this module. |
32528f94 | 628 | $info = get_fast_modinfo($this->course); |
5103b5e6 DS |
629 | if (!isset($info->cms[$this->cm->id])) { |
630 | // The course module has not been properly created in the course - undo everything. | |
a347aee3 | 631 | course_delete_module($this->cm->id); |
33b24bdd | 632 | throw new moodle_exception('errorcreatingactivity', 'moodle', '', $this->module->name); |
5103b5e6 | 633 | } |
0470a094 | 634 | $mod = $info->get_cm($this->cm->id); |
32528f94 | 635 | |
63deb5c3 | 636 | // Trigger course module created event. |
e20d3069 | 637 | $event = \core\event\course_module_created::create_from_cm($mod); |
63deb5c3 AA |
638 | $event->trigger(); |
639 | ||
32528f94 DS |
640 | $this->send_response($mod); |
641 | } | |
642 | ||
643 | /** | |
644 | * Send the details of the newly created activity back to the client browser | |
645 | * | |
646 | * @param cm_info $mod details of the mod just created | |
647 | */ | |
648 | protected function send_response($mod) { | |
9a36be73 | 649 | global $OUTPUT, $PAGE; |
abed5d65 | 650 | |
32528f94 DS |
651 | $resp = new stdClass(); |
652 | $resp->error = self::ERROR_OK; | |
9b2ad813 AN |
653 | $resp->elementid = 'module-' . $mod->id; |
654 | ||
655 | $courserenderer = $PAGE->get_renderer('core', 'course'); | |
656 | $completioninfo = new completion_info($this->course); | |
657 | $info = get_fast_modinfo($this->course); | |
658 | $sr = null; | |
659 | $modulehtml = $courserenderer->course_section_cm($this->course, $completioninfo, | |
660 | $mod, null, array()); | |
661 | $resp->fullcontent = $courserenderer->course_section_cm_list_item($this->course, $completioninfo, $mod, $sr); | |
d022f632 | 662 | |
abed5d65 | 663 | echo $OUTPUT->header(); |
32528f94 DS |
664 | echo json_encode($resp); |
665 | die(); | |
666 | } | |
3970a471 | 667 | } |