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