Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

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