MDL-11288 Added ability to duplicate module in the course
Internally, the new script modduplicate.php performs a single activity backup and restore and then moves the newly created copy right below the original.
This commit is contained in:
@@ -3160,6 +3160,10 @@ function make_editing_buttons($mod, $absolute=false, $moveselect=true, $indent=-
|
||||
'&sesskey='.$sesskey.$section.'"><img'.
|
||||
' src="'.$OUTPUT->pix_url('t/edit') . '" class="iconsmall" '.
|
||||
' alt="'.$str->update.'" /></a>'."\n".
|
||||
'<a class="editing_duplicate" title="'.$str->duplicate.'" href="'.$path.'/mod.php?duplicate='.$mod->id.
|
||||
'&sesskey='.$sesskey.$section.'"><img'.
|
||||
' src="'.$OUTPUT->pix_url('t/copy') . '" class="iconsmall" '.
|
||||
' alt="'.$str->duplicate.'" /></a>'."\n".
|
||||
'<a class="editing_delete" title="'.$str->delete.'" href="'.$path.'/mod.php?delete='.$mod->id.
|
||||
'&sesskey='.$sesskey.$section.'"><img'.
|
||||
' src="'.$OUTPUT->pix_url('t/delete') . '" class="iconsmall" '.
|
||||
|
||||
@@ -33,6 +33,7 @@ $add = optional_param('add', '', PARAM_ALPHA);
|
||||
$type = optional_param('type', '', PARAM_ALPHA);
|
||||
$indent = optional_param('indent', 0, PARAM_INT);
|
||||
$update = optional_param('update', 0, PARAM_INT);
|
||||
$duplicate = optional_param('duplicate', 0, PARAM_INT);
|
||||
$hide = optional_param('hide', 0, PARAM_INT);
|
||||
$show = optional_param('show', 0, PARAM_INT);
|
||||
$copy = optional_param('copy', 0, PARAM_INT);
|
||||
@@ -81,6 +82,42 @@ if (!empty($add)) {
|
||||
$returntomod = optional_param('return', 0, PARAM_BOOL);
|
||||
redirect("$CFG->wwwroot/course/modedit.php?update=$update&return=$returntomod");
|
||||
|
||||
} else if (!empty($duplicate)) {
|
||||
$cm = get_coursemodule_from_id('', $duplicate, 0, true, MUST_EXIST);
|
||||
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
|
||||
|
||||
require_login($course->id);
|
||||
$coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
|
||||
$modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
require_capability('moodle/course:manageactivities', $coursecontext);
|
||||
|
||||
if (!$confirm or !confirm_sesskey()) {
|
||||
$PAGE->set_title(get_string('duplicate'));
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->navbar->add(get_string('duplicatinga', 'core', format_string($cm->name)));
|
||||
$PAGE->set_pagelayout('incourse');
|
||||
|
||||
$a = new stdClass();
|
||||
$a->modtype = get_string('modulename', $cm->modname);
|
||||
$a->modname = format_string($cm->name);
|
||||
$a->modid = $cm->id;
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->confirm(
|
||||
get_string('duplicateconfirm', 'core', $a),
|
||||
new single_button(
|
||||
new moodle_url('/course/modduplicate.php', array('cmid' => $cm->id, 'course' => $course->id)),
|
||||
get_string('continue'),
|
||||
'post'),
|
||||
new single_button(
|
||||
new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $cm->course)),
|
||||
get_string('cancel'),
|
||||
'get')
|
||||
);
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
}
|
||||
|
||||
} else if (!empty($delete)) {
|
||||
if (!$cm = get_coursemodule_from_id('', $delete, 0, true)) {
|
||||
print_error('invalidcoursemodule');
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Duplicates a given course module
|
||||
*
|
||||
* The script backups and restores a single activity as if it was imported
|
||||
* from the same course, using the default import settings. The newly created
|
||||
* copy of the activity is then moved right below the original one.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage course
|
||||
* @copyright 2011 David Mudrak <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(dirname(dirname(__FILE__)) . '/config.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
$cmid = required_param('cmid', PARAM_INT);
|
||||
$courseid = required_param('course', PARAM_INT);
|
||||
|
||||
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
|
||||
$cm = get_coursemodule_from_id('', $cmid, $course->id, true, MUST_EXIST);
|
||||
$cmcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
$context = get_context_instance(CONTEXT_COURSE, $courseid);
|
||||
$section = $DB->get_record('course_sections', array('id' => $cm->section, 'course' => $cm->course));
|
||||
|
||||
require_login($course);
|
||||
require_sesskey();
|
||||
require_capability('moodle/course:manageactivities', $context);
|
||||
require_capability('moodle/backup:backuptargetimport', $context);
|
||||
require_capability('moodle/restore:restoretargetimport', $context);
|
||||
|
||||
$PAGE->set_title(get_string('duplicate'));
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->set_url(new moodle_url('/course/modduplicate.php', array('cmid' => $cm->id, 'courseid' => $course->id)));
|
||||
$PAGE->set_pagelayout('incourse');
|
||||
|
||||
$output = $PAGE->get_renderer('core', 'backup');
|
||||
|
||||
// backup the activity
|
||||
|
||||
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
|
||||
|
||||
$backupid = $bc->get_backupid();
|
||||
$backupbasepath = $bc->get_plan()->get_basepath();
|
||||
|
||||
$bc->execute_plan();
|
||||
|
||||
$bc->destroy();
|
||||
|
||||
// restore the backup immediately
|
||||
|
||||
$rc = new restore_controller($backupid, $courseid,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, backup::TARGET_CURRENT_ADDING);
|
||||
|
||||
if (!$rc->execute_precheck()) {
|
||||
$precheckresults = $rc->get_precheck_results();
|
||||
if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
|
||||
if (empty($CFG->keeptempdirectoriesonbackup)) {
|
||||
fulldelete($backupbasepath);
|
||||
}
|
||||
|
||||
echo $output->header();
|
||||
echo $output->precheck_notices($precheckresults);
|
||||
echo $output->continue_button(new moodle_url('/course/view.php', array('id' => $course->id)));
|
||||
echo $output->footer();
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
$rc->execute_plan();
|
||||
|
||||
// now a bit hacky part follows - we try to get the cmid of the newly
|
||||
// restored copy of the module
|
||||
$newcmid = null;
|
||||
$tasks = $rc->get_plan()->get_tasks();
|
||||
foreach ($tasks as $task) {
|
||||
if (is_subclass_of($task, 'restore_activity_task')) {
|
||||
if ($task->get_old_contextid() == $cmcontext->id) {
|
||||
$newcmid = $task->get_moduleid();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we know the cmid of the new course module, let us move it
|
||||
// right below the original one. otherwise it will stay at the
|
||||
// end of the section
|
||||
if ($newcmid) {
|
||||
$newcm = get_coursemodule_from_id('', $newcmid, $course->id, true, MUST_EXIST);
|
||||
moveto_module($newcm, $section, $cm);
|
||||
moveto_module($cm, $section, $newcm);
|
||||
}
|
||||
|
||||
$rc->destroy();
|
||||
|
||||
if (empty($CFG->keeptempdirectoriesonbackup)) {
|
||||
fulldelete($backupbasepath);
|
||||
}
|
||||
|
||||
$a = new stdClass();
|
||||
$a->modtype = get_string('modulename', $cm->modname);
|
||||
$a->modname = format_string($cm->name);
|
||||
|
||||
echo $output->header();
|
||||
|
||||
if ($newcmid) {
|
||||
echo $output->confirm(
|
||||
get_string('duplicatesuccess', 'core', $a),
|
||||
new single_button(
|
||||
new moodle_url('/course/modedit.php', array('update' => $newcmid)),
|
||||
get_string('duplicatecontedit'),
|
||||
'get'),
|
||||
new single_button(
|
||||
new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $cm->course)),
|
||||
get_string('duplicatecontcourse'),
|
||||
'get')
|
||||
);
|
||||
|
||||
} else {
|
||||
echo $output->notification(get_string('duplicatesuccess', 'core', $a), 'notifysuccess');
|
||||
echo $output->continue_button(
|
||||
new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $course->id))
|
||||
);
|
||||
}
|
||||
|
||||
echo $output->footer();
|
||||
+4
-1
@@ -461,8 +461,11 @@ $string['downloadods'] = 'Download in ODS format';
|
||||
$string['downloadtext'] = 'Download in text format';
|
||||
$string['doyouagree'] = 'Have you read these conditions and understood them?';
|
||||
$string['duplicate'] = 'Duplicate';
|
||||
$string['duplicateconfirm'] = 'Are you sure you want to duplicate {$a->modtype} \'{$a->modname}\' ?';
|
||||
$string['duplicatecontcourse'] = 'Return to the course';
|
||||
$string['duplicatecontedit'] = 'Edit the new copy';
|
||||
$string['duplicatesuccess'] = '{$a->modtype} \'{$a->modname}\' has been duplicated successfully';
|
||||
$string['duplicatinga'] = 'Duplicating: {$a}';
|
||||
$string['duplicatingain'] = 'Duplicating {$a->what} in {$a->in}';
|
||||
$string['edhelpaspellpath'] = 'To use spell-checking within the editor, you MUST have <strong>aspell 0.50</strong> or later installed on your server, and you must specify the correct path to access the aspell binary. On Unix/Linux systems, this path is usually <strong>/usr/bin/aspell</strong>, but it might be something else.';
|
||||
$string['edhelpbgcolor'] = 'Define the edit area\'s background color.<br />Valid values are, for example: #FFFFFF or white';
|
||||
$string['edhelpcleanword'] = 'This setting enables or disables Word-specific format filtering.';
|
||||
|
||||
@@ -631,6 +631,7 @@ resource_class.prototype.init_buttons = function() {
|
||||
var moveLeft = false;
|
||||
var moveRight = false;
|
||||
var updateButton = null;
|
||||
var duplicateButton = null;
|
||||
var assignButton = null;
|
||||
|
||||
// for RTL support
|
||||
@@ -643,6 +644,8 @@ resource_class.prototype.init_buttons = function() {
|
||||
moveRight = true;
|
||||
} else if (buttons[x].className == 'editing_update') {
|
||||
updateButton = buttons[x].cloneNode(true);
|
||||
} else if (buttons[x].className == 'editing_duplicate') {
|
||||
duplicateButton = buttons[x].cloneNode(true);
|
||||
} else if (buttons[x].className == 'editing_assign') {
|
||||
assignButton = buttons[x].cloneNode(true);
|
||||
} else if (buttons[x].className == 'editing_groupsnone') {
|
||||
@@ -691,6 +694,10 @@ resource_class.prototype.init_buttons = function() {
|
||||
// Add edit button back in.
|
||||
commandContainer.appendChild(updateButton);
|
||||
|
||||
if (duplicateButton) {
|
||||
commandContainer.appendChild(duplicateButton);
|
||||
}
|
||||
|
||||
// Add the delete button.
|
||||
var button = main.mk_button('a', main.portal.icons['delete'], main.portal.strings['delete'], null, [['class', 'iconsmall']]);
|
||||
YAHOO.util.Event.addListener(button, 'click', this.delete_button, this, true);
|
||||
|
||||
Reference in New Issue
Block a user