/**
  * Send one backup controller to DB
  *
  * @param backup_controller $controller controller to send to DB
  * @param string $checksum hash of the controller to be checked
  * @param bool $includeobj to decide if the object itself must be updated (true) or no (false)
  * @param bool $cleanobj to decide if the object itself must be cleaned (true) or no (false)
  * @return int id of the controller record in the DB
  * @throws backup_controller_exception|backup_dbops_exception
  */
 public static function save_controller($controller, $checksum, $includeobj = true, $cleanobj = false)
 {
     global $DB;
     // Check we are going to save one backup_controller
     if (!$controller instanceof backup_controller) {
         throw new backup_controller_exception('backup_controller_expected');
     }
     // Check checksum is ok. Only if we are including object info. Sounds silly but it isn't ;-).
     if ($includeobj and !$controller->is_checksum_correct($checksum)) {
         throw new backup_dbops_exception('backup_controller_dbops_saving_checksum_mismatch');
     }
     // Cannot request to $includeobj and $cleanobj at the same time.
     if ($includeobj and $cleanobj) {
         throw new backup_dbops_exception('backup_controller_dbops_saving_cannot_include_and_delete');
     }
     // Get all the columns
     $rec = new stdclass();
     $rec->backupid = $controller->get_backupid();
     $rec->operation = $controller->get_operation();
     $rec->type = $controller->get_type();
     $rec->itemid = $controller->get_id();
     $rec->format = $controller->get_format();
     $rec->interactive = $controller->get_interactive();
     $rec->purpose = $controller->get_mode();
     $rec->userid = $controller->get_userid();
     $rec->status = $controller->get_status();
     $rec->execution = $controller->get_execution();
     $rec->executiontime = $controller->get_executiontime();
     $rec->checksum = $checksum;
     // Serialize information
     if ($includeobj) {
         $rec->controller = base64_encode(serialize($controller));
     } else {
         if ($cleanobj) {
             $rec->controller = '';
         }
     }
     // Send it to DB
     if ($recexists = $DB->get_record('backup_controllers', array('backupid' => $rec->backupid))) {
         $rec->id = $recexists->id;
         $rec->timemodified = time();
         $DB->update_record('backup_controllers', $rec);
     } else {
         $rec->timecreated = time();
         $rec->timemodified = 0;
         $rec->id = $DB->insert_record('backup_controllers', $rec);
     }
     return $rec->id;
 }
 /**
  * Backs a course up and restores it.
  *
  * @param stdClass $course Course object to backup
  * @param int $newdate If non-zero, specifies custom date for new course
  * @return int ID of newly restored course
  */
 protected function backup_and_restore($course, $newdate = 0)
 {
     global $USER, $CFG;
     // Turn off file logging, otherwise it can't delete the file (Windows).
     $CFG->backup_file_logger_level = backup::LOG_NONE;
     // Do backup with default settings. MODE_IMPORT means it will just
     // create the directory and not zip it.
     $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
     $backupid = $bc->get_backupid();
     $bc->execute_plan();
     $bc->destroy();
     // Do restore to new course with default settings.
     $newcourseid = restore_dbops::create_new_course($course->fullname, $course->shortname . '_2', $course->category);
     $rc = new restore_controller($backupid, $newcourseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $USER->id, backup::TARGET_NEW_COURSE);
     if ($newdate) {
         $rc->get_plan()->get_setting('course_startdate')->set_value($newdate);
     }
     $this->assertTrue($rc->execute_precheck());
     $rc->execute_plan();
     $rc->destroy();
     return $newcourseid;
 }
Exemple #3
0
/**
 * Duplicate a module on the course.
 *
 * @param object $course The course
 * @param object $cm The course module to duplicate
 * @throws moodle_exception if the plugin doesn't support duplication
 * @return Object containing:
 * - fullcontent: The HTML markup for the created CM
 * - cmid: The CMID of the newly created CM
 * - redirect: Whether to trigger a redirect following this change
 */
function mod_duplicate_activity($course, $cm, $sr = null)
{
    global $CFG, $USER, $PAGE, $DB;
    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';
    $a = new stdClass();
    $a->modtype = get_string('modulename', $cm->modname);
    $a->modname = format_string($cm->name);
    if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) {
        throw new moodle_exception('duplicatenosupport', 'error');
    }
    // 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, $course->id, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, backup::TARGET_CURRENT_ADDING);
    $cmcontext = context_module::instance($cm->id);
    if (!$rc->execute_precheck()) {
        $precheckresults = $rc->get_precheck_results();
        if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
            if (empty($CFG->keeptempdirectoriesonbackup)) {
                fulldelete($backupbasepath);
            }
        }
    }
    $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) {
        error_log("Looking at a task");
        if (is_subclass_of($task, 'restore_activity_task')) {
            error_log("Looking at a restore_activity_task task");
            if ($task->get_old_contextid() == $cmcontext->id) {
                error_log("Contexts match");
                $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) {
        $info = get_fast_modinfo($course);
        $newcm = $info->get_cm($newcmid);
        $section = $DB->get_record('course_sections', array('id' => $cm->section, 'course' => $cm->course));
        moveto_module($newcm, $section, $cm);
        moveto_module($cm, $section, $newcm);
        // Trigger course module created event. We can trigger the event only if we know the newcmid.
        $event = \core\event\course_module_created::create_from_cm($newcm);
        $event->trigger();
    }
    rebuild_course_cache($cm->course);
    $rc->destroy();
    if (empty($CFG->keeptempdirectoriesonbackup)) {
        fulldelete($backupbasepath);
    }
    $resp = new stdClass();
    if ($newcm) {
        $courserenderer = $PAGE->get_renderer('core', 'course');
        $completioninfo = new completion_info($course);
        $modulehtml = $courserenderer->course_section_cm($course, $completioninfo, $newcm, null, array());
        $resp->fullcontent = $courserenderer->course_section_cm_list_item($course, $completioninfo, $newcm, $sr);
        $resp->cmid = $newcm->id;
    } else {
        // Trigger a redirect
        $resp->redirect = true;
    }
    return $resp;
}
 /**
  * Duplicates a single activity within a course.
  *
  * This is based on the code from course/modduplicate.php, but reduced for
  * simplicity.
  *
  * @param stdClass $course Course object
  * @param int $cmid Activity to duplicate
  * @return int ID of new activity
  */
 protected function duplicate($course, $cmid)
 {
     global $USER;
     // Do backup.
     $bc = new backup_controller(backup::TYPE_1ACTIVITY, $cmid, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
     $backupid = $bc->get_backupid();
     $bc->execute_plan();
     $bc->destroy();
     // Do restore.
     $rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, backup::TARGET_CURRENT_ADDING);
     $this->assertTrue($rc->execute_precheck());
     $rc->execute_plan();
     // Find cmid.
     $tasks = $rc->get_plan()->get_tasks();
     $cmcontext = context_module::instance($cmid);
     $newcmid = 0;
     foreach ($tasks as $task) {
         if (is_subclass_of($task, 'restore_activity_task')) {
             if ($task->get_old_contextid() == $cmcontext->id) {
                 $newcmid = $task->get_moduleid();
                 break;
             }
         }
     }
     $rc->destroy();
     if (!$newcmid) {
         throw new coding_exception('Unexpected: failure to find restored cmid');
     }
     return $newcmid;
 }
Exemple #5
0
/**
 * Api to duplicate a module.
 *
 * @param object $course course object.
 * @param object $cm course module object to be duplicated.
 * @since Moodle 2.8
 *
 * @throws Exception
 * @throws coding_exception
 * @throws moodle_exception
 * @throws restore_controller_exception
 *
 * @return cm_info|null cminfo object if we sucessfully duplicated the mod and found the new cm.
 */
function duplicate_module($course, $cm)
{
    global $CFG, $DB, $USER;
    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';
    $a = new stdClass();
    $a->modtype = get_string('modulename', $cm->modname);
    $a->modname = format_string($cm->name);
    if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) {
        throw new moodle_exception('duplicatenosupport', 'error', '', $a);
    }
    // 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, $course->id, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, backup::TARGET_CURRENT_ADDING);
    $cmcontext = context_module::instance($cm->id);
    if (!$rc->execute_precheck()) {
        $precheckresults = $rc->get_precheck_results();
        if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
            if (empty($CFG->keeptempdirectoriesonbackup)) {
                fulldelete($backupbasepath);
            }
        }
    }
    $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) {
        $info = get_fast_modinfo($course);
        $newcm = $info->get_cm($newcmid);
        $section = $DB->get_record('course_sections', array('id' => $cm->section, 'course' => $cm->course));
        moveto_module($newcm, $section, $cm);
        moveto_module($cm, $section, $newcm);
        // Update calendar events with the duplicated module.
        $refresheventsfunction = $newcm->modname . '_refresh_events';
        if (function_exists($refresheventsfunction)) {
            call_user_func($refresheventsfunction, $newcm->course);
        }
        // Trigger course module created event. We can trigger the event only if we know the newcmid.
        $event = \core\event\course_module_created::create_from_cm($newcm);
        $event->trigger();
    }
    rebuild_course_cache($cm->course);
    $rc->destroy();
    if (empty($CFG->keeptempdirectoriesonbackup)) {
        fulldelete($backupbasepath);
    }
    return isset($newcm) ? $newcm : null;
}
/**
 * Duplicates a Moodle module in an existing course
 * @param  int $cmid     Course module id
 * @param  int $courseid Course id
 * @return int           New course module id
 */
function local_ltiprovider_duplicate_module($cmid, $courseid, $newidnumber, $lticontext)
{
    global $CFG, $DB, $USER;
    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';
    if (empty($USER)) {
        // Emulate session.
        cron_setup_user();
    }
    $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
    $cm = get_coursemodule_from_id('', $cmid, 0, true, MUST_EXIST);
    $cmcontext = context_module::instance($cm->id);
    $context = context_course::instance($course->id);
    if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) {
        $url = course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn));
        print_error('duplicatenosupport', 'error', $url, $a);
    }
    // backup the activity
    $admin = get_admin();
    $bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $admin->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, $admin->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);
            }
            print_r($precheckresults);
            die;
        }
    }
    $rc->execute_plan();
    $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;
            }
        }
    }
    $rc->destroy();
    if ($module = $DB->get_record('course_modules', array('id' => $newcmid))) {
        $module->idnumber = $newidnumber;
        $DB->update_record('course_modules', $module);
    }
    $newtoolid = 0;
    if ($tools = $DB->get_records('local_ltiprovider', array('contextid' => $cmcontext->id))) {
        $newcmcontext = context_module::instance($newcmid);
        foreach ($tools as $tool) {
            $tool->courseid = $course->id;
            $tool->contextid = $newcmcontext->id;
            $newtoolid = $DB->insert_record('local_ltiprovider', $tool);
        }
    }
    if (!$newtoolid) {
        $tool = local_ltiprovider_create_tool($course->id, $newcmcontext->id, $lticontext);
    }
    if (empty($CFG->keeptempdirectoriesonbackup)) {
        fulldelete($backupbasepath);
    }
    return $newcmid;
}
Exemple #7
0
 /**
  * Duplicates a single dataform within a course.
  *
  * This is based on the code from course/modduplicate.php, but reduced for
  * simplicity.
  *
  * @param stdClass $course Course object
  * @param int $cmid Dataform to duplicate
  * @return stdClass The new dataform instance with cmid
  */
 public function duplicate_instance($course, $cmid)
 {
     global $DB, $USER;
     // Do backup.
     $bc = new backup_controller(backup::TYPE_1ACTIVITY, $cmid, 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();
     // Do restore.
     $rc = new restore_controller($backupid, $course->id, 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);
             }
         }
     }
     $rc->execute_plan();
     // Find cmid.
     $tasks = $rc->get_plan()->get_tasks();
     $cmcontext = context_module::instance($cmid);
     $newcmid = 0;
     $newactivityid = 0;
     foreach ($tasks as $task) {
         if (is_subclass_of($task, 'restore_activity_task')) {
             if ($task->get_old_contextid() == $cmcontext->id) {
                 $newcmid = $task->get_moduleid();
                 $newactivityid = $task->get_activityid();
                 break;
             }
         }
     }
     $rc->destroy();
     if (empty($CFG->keeptempdirectoriesonbackup)) {
         fulldelete($backupbasepath);
     }
     if (!$newcmid) {
         throw new coding_exception('Unexpected: failure to find restored cmid');
     }
     if (!($instance = $DB->get_record('dataform', array('id' => $newactivityid)))) {
         throw new coding_exception('Unexpected: failure to find restored activityid');
     }
     $instance->cmid = $newcmid;
     // Clear the time limit, otherwise phpunit complains.
     set_time_limit(0);
     return $instance;
 }
Exemple #8
0
 /**
  * Get the restore content tempdir.
  *
  * The tempdir is the sub directory in which the backup has been extracted.
  *
  * This caches the result for better performance, but $CFG->keeptempdirectoriesonbackup
  * needs to be enabled, otherwise the cache is ignored.
  *
  * @param string $backupfile path to a backup file.
  * @param string $shortname shortname of a course.
  * @param array $errors will be populated with errors found.
  * @return string|false false when the backup couldn't retrieved.
  */
 public static function get_restore_content_dir($backupfile = null, $shortname = null, &$errors = array())
 {
     global $CFG, $DB, $USER;
     $cachekey = null;
     if (!empty($backupfile)) {
         $backupfile = realpath($backupfile);
         if (empty($backupfile) || !is_readable($backupfile)) {
             $errors['cannotreadbackupfile'] = new lang_string('cannotreadbackupfile', 'tool_uploadcourse');
             return false;
         }
         $cachekey = 'backup_path:' . $backupfile;
     } else {
         if (!empty($shortname) || is_numeric($shortname)) {
             $cachekey = 'backup_sn:' . $shortname;
         }
     }
     if (empty($cachekey)) {
         return false;
     }
     // If $CFG->keeptempdirectoriesonbackup is not set to true, any restore happening would
     // automatically delete the backup directory... causing the cache to return an unexisting directory.
     $usecache = !empty($CFG->keeptempdirectoriesonbackup);
     if ($usecache) {
         $cache = cache::make('tool_uploadcourse', 'helper');
     }
     // If we don't use the cache, or if we do and not set, or the directory doesn't exist any more.
     if (!$usecache || (($backupid = $cache->get($cachekey)) === false || !is_dir("{$CFG->tempdir}/backup/{$backupid}"))) {
         // Use null instead of false because it would consider that the cache key has not been set.
         $backupid = null;
         if (!empty($backupfile)) {
             // Extracting the backup file.
             $packer = get_file_packer('application/vnd.moodle.backup');
             $backupid = restore_controller::get_tempdir_name(SITEID, $USER->id);
             $path = "{$CFG->tempdir}/backup/{$backupid}/";
             $result = $packer->extract_to_pathname($backupfile, $path);
             if (!$result) {
                 $errors['invalidbackupfile'] = new lang_string('invalidbackupfile', 'tool_uploadcourse');
             }
         } else {
             if (!empty($shortname) || is_numeric($shortname)) {
                 // Creating restore from an existing course.
                 $courseid = $DB->get_field('course', 'id', array('shortname' => $shortname), IGNORE_MISSING);
                 if (!empty($courseid)) {
                     $bc = new backup_controller(backup::TYPE_1COURSE, $courseid, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
                     $bc->execute_plan();
                     $backupid = $bc->get_backupid();
                     $bc->destroy();
                 } else {
                     $errors['coursetorestorefromdoesnotexist'] = new lang_string('coursetorestorefromdoesnotexist', 'tool_uploadcourse');
                 }
             }
         }
         if ($usecache) {
             $cache->set($cachekey, $backupid);
         }
     }
     if ($backupid === null) {
         $backupid = false;
     }
     return $backupid;
 }
Exemple #9
0
 /**
  * C'est une copie de la commande moosh
  * https://github.com/tmuras/moosh/blob/master/Moosh/Command/Moodle23/Course/CourseBackup.php
  * @param $shortname
  * @param $savepath
  */
 public static function execute($shortname, $savepath)
 {
     global $CFG, $DB, $USER;
     require_once $CFG->dirroot . '/backup/util/includes/backup_includes.php';
     error_reporting(E_ALL);
     ini_set('display_errors', true);
     //check if course id exists
     $course = $DB->get_record('course', array('shortname' => $shortname), '*', MUST_EXIST);
     $shortname = str_replace(' ', '_', $course->shortname);
     $filename = $savepath . '/backup_' . str_replace('/', '_', $shortname) . '_' . date('Y.m.d') . '.mbz';
     //check if destination file does not exist and can be created
     if (file_exists($filename)) {
         cli_error("File '{$filename}' already exists, I will not over-write it.");
     }
     $bc = new \backup_controller(\backup::TYPE_1COURSE, $course->id, \backup::FORMAT_MOODLE, \backup::INTERACTIVE_YES, \backup::MODE_GENERAL, 2);
     // 2 correspond à user admin!
     $tasks = $bc->get_plan()->get_tasks();
     foreach ($tasks as &$task) {
         if ($task instanceof \backup_root_task) {
             $setting = $task->get_setting('users');
             $setting->set_value('0');
             $setting = $task->get_setting('anonymize');
             $setting->set_value('1');
             $setting = $task->get_setting('role_assignments');
             $setting->set_value('1');
             $setting = $task->get_setting('filters');
             $setting->set_value('1');
             $setting = $task->get_setting('comments');
             $setting->set_value('0');
             $setting = $task->get_setting('logs');
             $setting->set_value('0');
             $setting = $task->get_setting('grade_histories');
             $setting->set_value('0');
         }
     }
     $bc->set_status(\backup::STATUS_AWAITING);
     $bc->execute_plan();
     $result = $bc->get_results();
     if (isset($result['backup_destination']) && $result['backup_destination']) {
         $file = $result['backup_destination'];
         /** @var $file stored_file */
         if (!$file->copy_content_to($filename)) {
             cli_error("Problems copying final backup to '" . $filename . "'");
         } else {
             printf("%s\n", $filename);
         }
     } else {
         echo $bc->get_backupid();
     }
 }
Exemple #10
0
 /**
  * Duplicate a course
  *
  * @param int $courseid
  * @param string $fullname Duplicated course fullname
  * @param string $shortname Duplicated course shortname
  * @param int $categoryid Duplicated course parent category id
  * @param int $visible Duplicated course availability
  * @param array $options List of backup options
  * @return array New course info
  * @since Moodle 2.3
  */
 public static function duplicate_course($courseid, $fullname, $shortname, $categoryid, $visible, $options)
 {
     global $CFG, $USER, $DB;
     require_once $CFG->dirroot . '/backup/util/includes/backup_includes.php';
     require_once $CFG->dirroot . '/backup/util/includes/restore_includes.php';
     // Parameter validation.
     $params = self::validate_parameters(self::duplicate_course_parameters(), array('courseid' => $courseid, 'fullname' => $fullname, 'shortname' => $shortname, 'categoryid' => $categoryid, 'visible' => $visible, 'options' => $options));
     // Context validation.
     if (!($course = $DB->get_record('course', array('id' => $params['courseid'])))) {
         throw new moodle_exception('invalidcourseid', 'error', '', $params['courseid']);
     }
     // Category where duplicated course is going to be created.
     $categorycontext = context_coursecat::instance($params['categoryid']);
     self::validate_context($categorycontext);
     // Course to be duplicated.
     $coursecontext = context_course::instance($course->id);
     self::validate_context($coursecontext);
     $backupdefaults = array('activities' => 1, 'blocks' => 1, 'filters' => 1, 'users' => 0, 'role_assignments' => 0, 'user_files' => 0, 'comments' => 0, 'completion_information' => 0, 'logs' => 0, 'histories' => 0);
     $backupsettings = array();
     // Check for backup and restore options.
     if (!empty($params['options'])) {
         foreach ($params['options'] as $option) {
             // Strict check for a correct value (allways 1 or 0, true or false).
             $value = clean_param($option['value'], PARAM_INT);
             if ($value !== 0 and $value !== 1) {
                 throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
             }
             if (!isset($backupdefaults[$option['name']])) {
                 throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
             }
             $backupsettings[$option['name']] = $value;
         }
     }
     // Capability checking.
     // The backup controller check for this currently, this may be redundant.
     require_capability('moodle/course:create', $categorycontext);
     require_capability('moodle/restore:restorecourse', $categorycontext);
     require_capability('moodle/backup:backupcourse', $coursecontext);
     if (!empty($backupsettings['users'])) {
         require_capability('moodle/backup:userinfo', $coursecontext);
         require_capability('moodle/restore:userinfo', $categorycontext);
     }
     // Check if the shortname is used.
     if ($foundcourses = $DB->get_records('course', array('shortname' => $shortname))) {
         foreach ($foundcourses as $foundcourse) {
             $foundcoursenames[] = $foundcourse->fullname;
         }
         $foundcoursenamestring = implode(',', $foundcoursenames);
         throw new moodle_exception('shortnametaken', '', '', $foundcoursenamestring);
     }
     // Backup the course.
     $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id);
     foreach ($backupsettings as $name => $value) {
         $bc->get_plan()->get_setting($name)->set_value($value);
     }
     $backupid = $bc->get_backupid();
     $backupbasepath = $bc->get_plan()->get_basepath();
     $bc->execute_plan();
     $results = $bc->get_results();
     $file = $results['backup_destination'];
     $bc->destroy();
     // Restore the backup immediately.
     // Check if we need to unzip the file because the backup temp dir does not contains backup files.
     if (!file_exists($backupbasepath . "/moodle_backup.xml")) {
         $file->extract_to_pathname(get_file_packer(), $backupbasepath);
     }
     // Create new course.
     $newcourseid = restore_dbops::create_new_course($params['fullname'], $params['shortname'], $params['categoryid']);
     $rc = new restore_controller($backupid, $newcourseid, backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id, backup::TARGET_NEW_COURSE);
     foreach ($backupsettings as $name => $value) {
         $setting = $rc->get_plan()->get_setting($name);
         if ($setting->get_status() == backup_setting::NOT_LOCKED) {
             $setting->set_value($value);
         }
     }
     if (!$rc->execute_precheck()) {
         $precheckresults = $rc->get_precheck_results();
         if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
             if (empty($CFG->keeptempdirectoriesonbackup)) {
                 fulldelete($backupbasepath);
             }
             $errorinfo = '';
             foreach ($precheckresults['errors'] as $error) {
                 $errorinfo .= $error;
             }
             if (array_key_exists('warnings', $precheckresults)) {
                 foreach ($precheckresults['warnings'] as $warning) {
                     $errorinfo .= $warning;
                 }
             }
             throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
         }
     }
     $rc->execute_plan();
     $rc->destroy();
     $course = $DB->get_record('course', array('id' => $newcourseid), '*', MUST_EXIST);
     $course->fullname = $params['fullname'];
     $course->shortname = $params['shortname'];
     $course->visible = $params['visible'];
     // Set shortname and fullname back.
     $DB->update_record('course', $course);
     if (empty($CFG->keeptempdirectoriesonbackup)) {
         fulldelete($backupbasepath);
     }
     // Delete the course backup file created by this WebService. Originally located in the course backups area.
     $file->delete();
     return array('id' => $course->id, 'shortname' => $course->shortname);
 }
Exemple #11
0
require_once '../../config.php';
require_once $CFG->dirroot . '/backup/util/includes/backup_includes.php';
require_once 'lib.php';
// Login
require_login();
// Backup
$course_module_to_backup = $course->id;
// Set this to one existing choice cmid in your dev site
$user_doing_the_backup = $USER->id;
// Set this to the id of your admin accouun
$bc = new backup_controller(backup::TYPE_1COURSE, $course_module_to_backup, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $user_doing_the_backup);
$bc->execute_plan();
require_once $CFG->dirroot . '/backup/util/includes/restore_includes.php';
// Restore
// Transaction.
$transaction = $DB->start_delegated_transaction();
// Create new course.
$folder = $bc->get_backupid();
$userdoingrestore = $USER->id;
// e.g. 2 == admin
$courseid = restore_dbops::create_new_course('', '', $categoryid);
// Restore backup into course.
$controller = new restore_controller($folder, $courseid, backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $userdoingrestore, backup::TARGET_NEW_COURSE);
$controller->execute_precheck();
$controller->execute_plan();
// Commit.
$transaction->allow_commit();
?>


Exemple #12
0
 function backup_template($courseid_from,$settings,$config,$admin) {
    $bc = new backup_controller(backup::TYPE_1COURSE, $courseid_from, backup::FORMAT_MOODLE,
                                backup::INTERACTIVE_YES, backup::MODE_IMPORT,$admin->id);
    $backupid = $bc->get_backupid();
    $bc->get_plan()->get_setting('users')->set_status(backup_setting::LOCKED_BY_CONFIG);
    
    foreach ($settings as $setting => $configsetting) {
        if ($bc->get_plan()->setting_exists($setting)) {
            $bc->get_plan()->get_setting($setting)->set_value($config->{$configsetting});
        }
    }
 
    $bc->finish_ui();
    $bc->execute_plan();
    $bc->destroy();
    unset($bc);
 
    return $backupid;
}
Exemple #13
0
 public function test_mod_jclic_duplicate()
 {
     global $USER, $DB, $CFG;
     require_once $CFG->dirroot . '/backup/util/includes/backup_includes.php';
     require_once $CFG->dirroot . '/backup/util/includes/restore_includes.php';
     $this->resetAfterTest(true);
     $this->setUser(2);
     // Admin user.
     // Create a course with some availability data set.
     $generator = $this->getDataGenerator();
     $course = $generator->create_course(array('format' => 'topics', 'numsections' => 3, 'enablecompletion' => COMPLETION_ENABLED), array('createsections' => true));
     $jclic = $generator->create_module('jclic', array('course' => $course->id));
     $cmid = $jclic->cmid;
     // Do backup.
     $bc = new backup_controller(backup::TYPE_1ACTIVITY, $cmid, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
     $backupid = $bc->get_backupid();
     $bc->execute_plan();
     $bc->destroy();
     // Do restore.
     $rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, backup::TARGET_CURRENT_ADDING);
     $this->assertTrue($rc->execute_precheck());
     $rc->execute_plan();
     // Find cmid.
     $tasks = $rc->get_plan()->get_tasks();
     $cmcontext = context_module::instance($cmid);
     $newcmid = 0;
     foreach ($tasks as $task) {
         if (is_subclass_of($task, 'restore_activity_task')) {
             if ($task->get_old_contextid() == $cmcontext->id) {
                 $newcmid = $task->get_moduleid();
                 break;
             }
         }
     }
     $rc->destroy();
     if (!$newcmid) {
         throw new coding_exception('Unexpected: failure to find restored cmid');
     }
     // Check settings in new course.
     $newjclic = new jclic(context_module::instance($newcmid), false, false);
     $newjclicmodule = $newjclic->get_instance();
     $this->assertNotEmpty($newjclic);
     $jclic = new jclic(context_module::instance($jclic->cmid), false, false);
     $jclicmodule = $jclic->get_instance();
     $fields = (array) $jclicmodule;
     unset($fields['id']);
     unset($fields['course']);
     foreach ($fields as $key => $unused) {
         $this->assertEquals($newjclicmodule->{$key}, $jclicmodule->{$key}, "Failed on field {$key}");
     }
     // Avoid errors...
     ini_set('max_execution_time', 0);
 }
Exemple #14
0
 /**
  * Tests the restore_controller.
  */
 public function test_restore_controller_is_executing()
 {
     global $CFG;
     // Make a backup.
     check_dir_exists($CFG->tempdir . '/backup');
     $bc = new backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $this->userid);
     $backupid = $bc->get_backupid();
     $bc->execute_plan();
     $bc->destroy();
     // The progress class will get called during restore, so we can use that
     // to check the executing flag is true.
     $progress = new core_backup_progress_restore_is_executing();
     // Set up restore.
     $rc = new restore_controller($backupid, $this->courseid, backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $this->userid, backup::TARGET_EXISTING_ADDING);
     $this->assertTrue($rc->execute_precheck());
     // Check restore is NOT executing.
     $this->assertFalse(restore_controller::is_executing());
     // Execute restore.
     $rc->set_progress($progress);
     $rc->execute_plan();
     // Check restore is NOT executing afterward either.
     $this->assertFalse(restore_controller::is_executing());
     $rc->destroy();
     // During restore, check that executing was true.
     $this->assertTrue(count($progress->executing) > 0);
     $alltrue = true;
     foreach ($progress->executing as $executing) {
         if (!$executing) {
             $alltrue = false;
             break;
         }
     }
     $this->assertTrue($alltrue);
 }
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');
$a = new stdClass();
$a->modtype = get_string('modulename', $cm->modname);
$a->modname = format_string($cm->name);
if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) {
    $url = course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn));
    print_error('duplicatenosupport', 'error', $url, $a);
}
// 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);
        $url = course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn));
        echo $output->continue_button($url);
 /**
  * Takes the original course object as an argument, backs up the
  * course and returns a backupid which can be used for restoring the course.
  *
  * @param object $course Original course object
  * @param array $activityids all cm ids to backup
  * @param array $activityids all section ids to backup
  * @throws coding_exception Moodle coding_exception
  * @retun string backupid Backupid
  */
 private function backup($course, $activityids, $sectionids)
 {
     global $CFG, $DB, $USER;
     // MODE_IMPORT option is required to prevent it from zipping up the
     // result at the end. Unfortunately this breaks the system in some
     // other ways (see other comments).
     // NOTE: We cannot use MODE_SAMESITE here because that option will
     // zip the result and anyway, MODE_IMPORT already turns off the files.
     $bc = new \backup_controller(\backup::TYPE_1COURSE, $course->id, \backup::FORMAT_MOODLE, \backup::INTERACTIVE_NO, \backup::MODE_IMPORT, $USER->id);
     // Setup custom logger that prints dots.
     $logger = new logger(\backup::LOG_INFO, false, true);
     self::$currentlogger = $logger;
     $logger->potential_dot();
     $bc->get_logger()->set_next($logger);
     $bc->set_progress(new progress());
     foreach ($bc->get_plan()->get_tasks() as $taskindex => $task) {
         $settings = $task->get_settings();
         foreach ($settings as $settingindex => $setting) {
             $setting->set_status(\backup_setting::NOT_LOCKED);
             // Modify the values of the intial backup settings.
             if ($taskindex == 0) {
                 if (isset($this->backupsettings[$setting->get_name()])) {
                     $setting->set_value($this->backupsettings[$setting->get_name()]);
                 }
             } else {
                 list($name, $id, $type) = $this->parse_backup_course_module($setting->get_name());
                 // Include user data on glossary if the role 'contributingstudent'
                 // does not have the capability mod/glossary:write on that glossary.
                 // This is so that we include course-team glossary data but not
                 // glossaries that are written by students.
                 if ($name === 'glossary' && $type === 'userinfo') {
                     // Find the contributing student role id. If there
                     // isn't one, use the student role id, for dev servers etc.
                     $roles = $DB->get_records_select('role', "shortname IN ('contributingstudent', 'student')", null, 'shortname', 'id');
                     if (!$roles) {
                         continue;
                     }
                     $roleid = reset($roles)->id;
                     // Get the list of roles which have the capability in the context
                     // of the glossary.
                     $context = \context_module::instance($id);
                     list($allowed, $forbidden) = get_roles_with_cap_in_context($context, 'mod/glossary:write');
                     // If student has this capability then the user data is false.
                     if (!empty($allowed[$roleid]) && empty($forbidden[$roleid])) {
                         $setting->set_value(false);
                     } else {
                         $setting->set_value(true);
                     }
                 }
                 // Ignone any sections not in subpage.
                 if ($name === 'section' && $type === 'included' && !in_array($id, $sectionids)) {
                     $setting->set_value(false);
                 }
                 // Ignone any activities not in subpage.
                 if ($name !== 'section' && $type === 'included' && !in_array($id, $activityids)) {
                     $setting->set_value(false);
                 }
             }
         }
     }
     $logger->potential_dot();
     $bc->save_controller();
     $backupid = $bc->get_backupid();
     $this->backupbasepath = $bc->get_plan()->get_basepath();
     $bc->execute_plan();
     $bc->destroy();
     return $backupid;
 }
Exemple #17
0
    /**
     * Imports a course
     *
     * @param int $importfrom The id of the course we are importing from
     * @param int $importto The id of the course we are importing to
     * @param bool $deletecontent Whether to delete the course we are importing to content
     * @param array $options List of backup options
     * @return null
     * @since Moodle 2.4
     */
    public static function import_course($importfrom, $importto, $deletecontent = 0, $options = array()) {
        global $CFG, $USER, $DB;
        require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
        require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');

        // Parameter validation.
        $params = self::validate_parameters(
            self::import_course_parameters(),
            array(
                'importfrom' => $importfrom,
                'importto' => $importto,
                'deletecontent' => $deletecontent,
                'options' => $options
            )
        );

        if ($params['deletecontent'] !== 0 and $params['deletecontent'] !== 1) {
            throw new moodle_exception('invalidextparam', 'webservice', '', $params['deletecontent']);
        }

        // Context validation.

        if (! ($importfrom = $DB->get_record('course', array('id'=>$params['importfrom'])))) {
            throw new moodle_exception('invalidcourseid', 'error');
        }

        if (! ($importto = $DB->get_record('course', array('id'=>$params['importto'])))) {
            throw new moodle_exception('invalidcourseid', 'error');
        }

        $importfromcontext = context_course::instance($importfrom->id);
        self::validate_context($importfromcontext);

        $importtocontext = context_course::instance($importto->id);
        self::validate_context($importtocontext);

        $backupdefaults = array(
            'activities' => 1,
            'blocks' => 1,
            'filters' => 1
        );

        $backupsettings = array();

        // Check for backup and restore options.
        if (!empty($params['options'])) {
            foreach ($params['options'] as $option) {

                // Strict check for a correct value (allways 1 or 0, true or false).
                $value = clean_param($option['value'], PARAM_INT);

                if ($value !== 0 and $value !== 1) {
                    throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
                }

                if (!isset($backupdefaults[$option['name']])) {
                    throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
                }

                $backupsettings[$option['name']] = $value;
            }
        }

        // Capability checking.

        require_capability('moodle/backup:backuptargetimport', $importfromcontext);
        require_capability('moodle/restore:restoretargetimport', $importtocontext);

        $bc = new backup_controller(backup::TYPE_1COURSE, $importfrom->id, backup::FORMAT_MOODLE,
                backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);

        foreach ($backupsettings as $name => $value) {
            $bc->get_plan()->get_setting($name)->set_value($value);
        }

        $backupid       = $bc->get_backupid();
        $backupbasepath = $bc->get_plan()->get_basepath();

        $bc->execute_plan();
        $bc->destroy();

        // Restore the backup immediately.

        // Check if we must delete the contents of the destination course.
        if ($params['deletecontent']) {
            $restoretarget = backup::TARGET_EXISTING_DELETING;
        } else {
            $restoretarget = backup::TARGET_EXISTING_ADDING;
        }

        $rc = new restore_controller($backupid, $importto->id,
                backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, $restoretarget);

        foreach ($backupsettings as $name => $value) {
            $rc->get_plan()->get_setting($name)->set_value($value);
        }

        if (!$rc->execute_precheck()) {
            $precheckresults = $rc->get_precheck_results();
            if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
                if (empty($CFG->keeptempdirectoriesonbackup)) {
                    fulldelete($backupbasepath);
                }

                $errorinfo = '';

                foreach ($precheckresults['errors'] as $error) {
                    $errorinfo .= $error;
                }

                if (array_key_exists('warnings', $precheckresults)) {
                    foreach ($precheckresults['warnings'] as $warning) {
                        $errorinfo .= $warning;
                    }
                }

                throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
            }
        } else {
            if ($restoretarget == backup::TARGET_EXISTING_DELETING) {
                restore_dbops::delete_course_content($importto->id);
            }
        }

        $rc->execute_plan();
        $rc->destroy();

        if (empty($CFG->keeptempdirectoriesonbackup)) {
            fulldelete($backupbasepath);
        }

        return null;
    }
 /**
  * Returns welcome message.
  * @param string $sourcecourse
  * @param string $destinationcourse
  * @param bool $excludequestionbank
  * @return string welcome message.
  */
 public static function copy_content($sourcecourse = '', $destinationcourse = '', $excludequestionbank = false)
 {
     global $DB;
     try {
         $courseid = $destinationcourse;
         $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
         // The id of the course we are importing FROM (will only be set if past first stage.
         $importcourseid = $sourcecourse;
         // The target method for the restore (adding or deleting).
         $restoretarget = backup::TARGET_EXISTING_DELETING;
         $importcourse = $DB->get_record('course', array('id' => $importcourseid), '*', MUST_EXIST);
         $bc = new backup_controller(backup::TYPE_1COURSE, $importcourse->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT, 2);
         $bc->get_plan()->get_setting('users')->set_status(backup_setting::LOCKED_BY_CONFIG);
         $settings = $bc->get_plan()->get_settings();
         // If excludequestionbank is set, do not backup question bank.
         if ($excludequestionbank && $bc->get_plan()->setting_exists('questionbank')) {
             $setting = $bc->get_plan()->get_setting('questionbank');
             $setting->set_value(0);
         }
         // For the initial stage we want to hide all locked settings and if there are.
         // No visible settings move to the next stage.
         foreach ($settings as $setting) {
             if ($setting->get_status() !== backup_setting::NOT_LOCKED) {
                 $setting->set_visibility(backup_setting::HIDDEN);
             }
         }
         $backupid = $bc->get_backupid();
         $bc->execute_plan();
         restore_dbops::delete_course_content($course->id);
         $rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2, $restoretarget);
         $rc->execute_precheck();
         // If excludequestionbank is set, do not restore quizzes.
         if ($excludequestionbank) {
             $settings = $rc->get_plan()->get_settings();
             foreach ($settings as $setting) {
                 if (preg_match('/(quiz)(_)(\\d+)(_)(included)/', $setting->get_name())) {
                     $rc->get_plan()->get_setting($setting->get_name())->set_value(0);
                 }
             }
         }
         $rc->execute_plan();
         $results = $rc->get_results();
         if (isset($results["file_missing_in_backup"])) {
             if (extension_loaded('newrelic')) {
                 newrelic_notice_error($results["file_missing_in_backup"], new Exception('Missing file in backup'));
             }
         }
         $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
         $importcourse->id = $course->id;
         $importcourse->modinfo = $course->modinfo;
         $importcourse->idnumber = $course->idnumber;
         $importcourse->fullname = $course->fullname;
         $importcourse->shortname = $course->shortname;
         $importcourse->startdate = $course->startdate;
         $importcourse->sectioncache = null;
         $sourceformat = $DB->get_field('course', 'format', array('id' => $importcourseid), MUST_EXIST);
         if (!($coursenumsections = $DB->get_field('course_format_options', 'value', array('courseid' => $importcourseid, 'name' => 'numsections', 'format' => $sourceformat)))) {
             $coursenumsections = 10;
         }
         if ($courseformatconfig = $DB->get_record('course_format_options', array('courseid' => $course->id, 'name' => 'numsections', 'format' => $sourceformat))) {
             $courseformatconfig->value = $coursenumsections;
             $DB->update_record('course_format_options', $courseformatconfig);
         } else {
             $courseformatconfig = new stdClass();
             $courseformatconfig->courseid = $course->id;
             $courseformatconfig->name = 'numsections';
             $courseformatconfig->value = $coursenumsections;
             $courseformatconfig->format = $sourceformat;
             $courseformatconfig->sectionid = 0;
             $DB->insert_record('course_format_options', $courseformatconfig);
         }
         $DB->update_record('course', $importcourse);
         return 'success';
     } catch (Exception $e) {
         if (extension_loaded('newrelic')) {
             newrelic_notice_error($e->getMessage(), $e);
         }
         return 'Exception ' . $e->getMessage();
     }
 }