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