This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE
data available
333840
public function process_choice($data) {

        // get the course module id and context id
        $instanceid     = $data['id'];
        $cminfo         = $this->get_cminfo($instanceid);
        $this->moduleid = $cminfo['id'];
        $contextid      = $this->converter->get_contextid(CONTEXT_MODULE, $this->moduleid);

        // get a fresh new file manager for this instance
        $this->fileman = $this->converter->get_file_manager($contextid, 'mod_choice');

        // convert course files embedded into the intro
        $this->fileman->filearea = 'intro';
        $this->fileman->itemid   = 0;
        $data['intro'] = moodle1_converter::migrate_referenced_files($data['intro'], $this->fileman);

        // start writing choice.xml
        $this->open_xml_writer("activities/choice_{$this->moduleid}/choice.xml");
        $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
            'modulename' => 'choice', 'contextid' => $contextid));
        $this->xmlwriter->begin_tag('choice', array('id' => $instanceid));

        foreach ($data as $field => $value) {
            if ($field <> 'id') {
                $this->xmlwriter->full_tag($field, $value);
            }
        }

        return $data;
    }
14265
protected function create_course_module() {
        global $CFG;
        require_once($CFG->dirroot.'/course/modlib.php');
        list($module, $context, $cw, $cm, $data) = prepare_new_moduleinfo_data($this->course, $this->module->name, $this->section);

        $data->coursemodule = $data->id = add_course_module($data);
        $this->cm = $data;
    }
805686
public function load_choices() {
        if (is_array($this->choices)) {
            return true;
        }
        $this->choices = array();

        global $CFG, $DB;
        $records = $DB->get_records('modules', array('visible'=>1), 'name');
        foreach ($records as $record) {
            // Exclude modules if the code doesn't exist
            if (file_exists("$CFG->dirroot/mod/$record->name/lib.php")) {
                // Also exclude system modules (if specified)
                if (!($this->excludesystem &&
                        plugin_supports('mod', $record->name, FEATURE_MOD_ARCHETYPE) ===
                        MOD_ARCHETYPE_SYSTEM)) {
                    $this->choices[$record->id] = $record->name;
                }
            }
        }
        return true;
    }
335220
protected function finish_setup_course_module($instanceid) {
        global $DB, $USER;

        if (!$instanceid) {
            // Something has gone wrong - undo everything we can.
            course_delete_module($this->cm->id);
            throw new moodle_exception('errorcreatingactivity', 'moodle', '', $this->module->name);
        }

        // Note the section visibility
        $visible = get_fast_modinfo($this->course)->get_section_info($this->section)->visible;

        $DB->set_field('course_modules', 'instance', $instanceid, array('id' => $this->cm->id));
        // Rebuild the course cache after update action
        rebuild_course_cache($this->course->id, true);

        $sectionid = course_add_cm_to_section($this->course, $this->cm->id, $this->section);

        set_coursemodule_visible($this->cm->id, $visible);
        if (!$visible) {
            $DB->set_field('course_modules', 'visibleold', 1, array('id' => $this->cm->id));
        }

        // retrieve the final info about this module.
        $info = get_fast_modinfo($this->course);
        if (!isset($info->cms[$this->cm->id])) {
            // The course module has not been properly created in the course - undo everything.
            course_delete_module($this->cm->id);
            throw new moodle_exception('errorcreatingactivity', 'moodle', '', $this->module->name);
        }
        $mod = $info->get_cm($this->cm->id);

        // Trigger course module created event.
        $event = \core\event\course_module_created::create_from_cm($mod);
        $event->trigger();

        $this->send_response($mod);
    }
928858
public function process_scorm($data) {
        global $CFG;

        // get the course module id and context id
        $instanceid     = $data['id'];
        $currentcminfo  = $this->get_cminfo($instanceid);
        $this->moduleid = $currentcminfo['id'];
        $contextid      = $this->converter->get_contextid(CONTEXT_MODULE, $this->moduleid);

        // conditionally migrate to html format in intro
        if ($CFG->texteditors !== 'textarea') {
            $data['intro']       = text_to_html($data['intro'], false, false, true);
            $data['introformat'] = FORMAT_HTML;
        }

        // get a fresh new file manager for this instance
        $this->fileman = $this->converter->get_file_manager($contextid, 'mod_scorm');

        // convert course files embedded into the intro
        $this->fileman->filearea = 'intro';
        $this->fileman->itemid   = 0;
        $data['intro'] = moodle1_converter::migrate_referenced_files($data['intro'], $this->fileman);

        // check 1.9 version where backup was created
        $backupinfo = $this->converter->get_stash('backup_info');
        if ($backupinfo['moodle_version'] < 2007110503) {
            // as we have no module version data, assume $currmodule->version <= $module->version
            // - fix data as the source 1.9 build hadn't yet at time of backing up.
            $data['grademethod'] = $data['grademethod']%10;
        }

        // update scormtype (logic is consistent as done in scorm/db/upgrade.php)
        $ismanifest = preg_match('/imsmanifest\.xml$/', $data['reference']);
        $iszippif = preg_match('/.(zip|pif)$/', $data['reference']);
        $isurl = preg_match('/^((http|https):\/\/|www\.)/', $data['reference']);
        if ($isurl) {
            if ($ismanifest) {
                $data['scormtype'] = 'external';
            } else if ($iszippif) {
                $data['scormtype'] = 'localtype';
            }
        }

        // migrate scorm package file
        $this->fileman->filearea = 'package';
        $this->fileman->itemid   = 0;
        $this->fileman->migrate_file('course_files/'.$data['reference']);

        // start writing scorm.xml
        $this->open_xml_writer("activities/scorm_{$this->moduleid}/scorm.xml");
        $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
            'modulename' => 'scorm', 'contextid' => $contextid));
        $this->xmlwriter->begin_tag('scorm', array('id' => $instanceid));

        foreach ($data as $field => $value) {
            if ($field <> 'id') {
                $this->xmlwriter->full_tag($field, $value);
            }
        }

        $this->xmlwriter->begin_tag('scoes');

        return $data;
    }
766546
public function course_section_cm_availability(cm_info $mod, $displayoptions = array()) {
        global $CFG;
        $output = '';
        if (!$mod->is_visible_on_course_page()) {
            return $output;
        }
        if (!$mod->uservisible) {
            // this is a student who is not allowed to see the module but might be allowed
            // to see availability info (i.e. "Available from ...")
            if (!empty($mod->availableinfo)) {
                $formattedinfo = \core_availability\info::format_info(
                        $mod->availableinfo, $mod->get_course());
                $output = $this->availability_info($formattedinfo, 'isrestricted');
            }
            return $output;
        }
        // this is a teacher who is allowed to see module but still should see the
        // information that module is not available to all/some students
        $modcontext = context_module::instance($mod->id);
        $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $modcontext);
        if ($canviewhidden && !$mod->visible) {
            // This module is hidden but current user has capability to see it.
            // Do not display the availability info if the whole section is hidden.
            if ($mod->get_section_info()->visible) {
                $output .= $this->availability_info(get_string('hiddenfromstudents'), 'ishidden');
            }
        } else if ($mod->is_stealth()) {
            // This module is available but is normally not displayed on the course page
            // (this user can see it because they can manage it).
            $output .= $this->availability_info(get_string('hiddenoncoursepage'), 'isstealth');
        }
        if ($canviewhidden && !empty($CFG->enableavailability)) {
            // Display information about conditional availability.
            // Don't add availability information if user is not editing and activity is hidden.
            if ($mod->visible || $this->page->user_is_editing()) {
                $hidinfoclass = 'isrestricted isfullinfo';
                if (!$mod->visible) {
                    $hidinfoclass .= ' hide';
                }
                $ci = new \core_availability\info_module($mod);
                $fullinfo = $ci->get_full_information();
                if ($fullinfo) {
                    $formattedinfo = \core_availability\info::format_info(
                            $fullinfo, $mod->get_course());
                    $output .= $this->availability_info($formattedinfo, $hidinfoclass);
                }
            }
        }
        return $output;
    }
108271
public function runModule()
    {
        if ($this->status->run === true) {
            return;
        }
        
        $runnerFile   = $this->obtainRunnerFile();
        $initFunction = function() use ($runnerFile) {
            if (empty($runnerFile)) {
                return;
            }
            
            require(realpath($runnerFile));
        };

        $this->status->run = true;
        $initFunction();
    }
186437
public function execute() {
        global $CFG;
        require_once($CFG->dirroot. '/course/lib.php');

        // Set the proper user.
        if ($this->get_custom_data()->userid !== $this->get_custom_data()->realuserid) {
            $realuser = \core_user::get_user($this->get_custom_data()->realuserid, '*', MUST_EXIST);
            cron_setup_user($realuser);
            \core\session\manager::loginas($this->get_custom_data()->userid, \context_system::instance(), false);
        } else {
            $user = \core_user::get_user($this->get_custom_data()->userid, '*', MUST_EXIST);
            cron_setup_user($user);
        }

        $cms = $this->get_custom_data()->cms;
        foreach ($cms as $cm) {
            try {
                course_delete_module($cm->id);
            } catch (\Exception $e) {
                throw new \coding_exception("The course module {$cm->id} could not be deleted. {$e->getTraceAsString()}");
            }
        }
    }
436473
public function store_item($cm) {
        global $CFG, $DB;

        require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');

        // Get more information.
        $modinfo = get_fast_modinfo($cm->course);

        if (!isset($modinfo->cms[$cm->id])) {
            return; // Can't continue without the module information.
        }

        $cminfo = $modinfo->cms[$cm->id];

        // Check backup/restore support.
        if (!plugin_supports('mod', $cminfo->modname , FEATURE_BACKUP_MOODLE2)) {
            return;
        }

        // As far as recycle bin is using MODE_AUTOMATED, it observes the backup_auto_storage
        // setting (storing backups @ real location. For recycle bin we want to ensure that
        // backup files are always stored in Moodle file area. In order to achieve that, we
        // hack the setting here via $CFG->forced_plugin_settings, so it won't interfere other
        // operations.  See MDL-65218 for more information.
        // This hack will be removed once recycle bin switches to use its own backup mode, with
        // own preferences and 100% appart from MODLE_AUTOMATED.
        // TODO: Remove this as part of MDL-65228.
        $CFG->forced_plugin_settings['backup'] = ['backup_auto_storage' => 0];

        // Backup the activity.
        $user = get_admin();
        $controller = new \backup_controller(
            \backup::TYPE_1ACTIVITY,
            $cm->id,
            \backup::FORMAT_MOODLE,
            \backup::INTERACTIVE_NO,
            \backup::MODE_AUTOMATED,
            $user->id
        );
        $controller->execute_plan();

        // We don't need the forced setting anymore, hence unsetting it.
        // TODO: Remove this as part of MDL-65228.
        unset($CFG->forced_plugin_settings['backup']);

        // Grab the result.
        $result = $controller->get_results();
        if (!isset($result['backup_destination'])) {
            throw new \moodle_exception('Failed to backup activity prior to deletion.');
        }

        // Have finished with the controller, let's destroy it, freeing mem and resources.
        $controller->destroy();

        // Grab the filename.
        $file = $result['backup_destination'];
        if (!$file->get_contenthash()) {
            throw new \moodle_exception('Failed to backup activity prior to deletion (invalid file).');
        }

        // Record the activity, get an ID.
        $activity = new \stdClass();
        $activity->courseid = $cm->course;
        $activity->section = $cm->section;
        $activity->module = $cm->module;
        $activity->name = $cminfo->name;
        $activity->timecreated = time();
        $binid = $DB->insert_record('tool_recyclebin_course', $activity);

        // Create the location we want to copy this file to.
        $filerecord = array(
            'contextid' => \context_course::instance($this->_courseid)->id,
            'component' => 'tool_recyclebin',
            'filearea' => TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA,
            'itemid' => $binid,
            'timemodified' => time()
        );

        // Move the file to our own special little place.
        $fs = get_file_storage();
        if (!$fs->create_file_from_storedfile($filerecord, $file)) {
            // Failed, cleanup first.
            $DB->delete_records('tool_recyclebin_course', array(
                'id' => $binid
            ));

            throw new \moodle_exception("Failed to copy backup file to recyclebin.");
        }

        // Delete the old file.
        $file->delete();

        // Fire event.
        $event = \tool_recyclebin\event\course_bin_item_created::create(array(
            'objectid' => $binid,
            'context' => \context_course::instance($cm->course)
        ));
        $event->trigger();
    }
1262846
def _post_execute(self):
        

        if self.todolist.dirty:
            # do not archive when the value of the filename is an empty string
            # (i.e. explicitly left empty in the configuration
            if self.do_archive and config().archive():
                self._archive()
            elif config().archive() and self.backup:
                archive = _retrieve_archive()[0]
                self.backup.add_archive(archive)

            self._post_archive_action()

            if config().keep_sorted():
                from topydo.commands.SortCommand import SortCommand
                self._execute(SortCommand, [])

            if self.backup:
                self.backup.save(self.todolist)

            self.todofile.write(self.todolist.print_todos())
            self.todolist.dirty = False

        self.backup = None
1097080
public function process_basiclti($data) {
        global $DB;

        // Get the course module id and context id.
        $instanceid     = $data['id'];
        $cminfo         = $this->get_cminfo($instanceid);
        $this->moduleid = $cminfo['id'];
        $contextid      = $this->converter->get_contextid(CONTEXT_MODULE, $this->moduleid);

        // Get a fresh new file manager for this instance.
        $this->fileman = $this->converter->get_file_manager($contextid, 'mod_lti');

        // Convert course files embedded into the intro.
        $this->fileman->filearea = 'intro';
        $this->fileman->itemid   = 0;
        $data['intro'] = moodle1_converter::migrate_referenced_files($data['intro'], $this->fileman);

        // Start writing assignment.xml.
        $this->open_xml_writer("activities/lti_{$this->moduleid}/lti.xml");
        $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
                'modulename' => 'lti', 'contextid' => $contextid));
        $this->xmlwriter->begin_tag('lti', array('id' => $instanceid));

        $ignorefields = array('id', 'modtype');
        if (!$DB->record_exists('lti_types', array('id' => $data['typeid']))) {
            $ntypeid = false;
            $toolurls = $DB->get_records_select(
                    'lti_types_config',
                    "name = 'toolurl' AND " . $DB->sql_compare_text('value', 256) . ' = ' .  $DB->sql_compare_text('?', 256),
                    [$data['toolurl']],
                    '',
                    'id, value'
                );
            foreach ($toolurls as $id => $value) {
                if ($value == $data['toolurl']) {
                    $ntypeid = $id;
                    break;
                }
            }
            if ($ntypeid === false) {
                $ntypeid = $DB->get_field('lti_types_config',
                                          'typeid',
                                          array(),
                                          IGNORE_MULTIPLE);

            }
            if ($ntypeid === false) {
                $ntypeid = 0;
            }
            $data['typeid'] = $ntypeid;
        }
        if (empty($data['servicesalt'])) {
            $data['servicesalt'] = uniqid('', true);
        }
        foreach ($data as $field => $value) {
            if (!in_array($field, $ignorefields)) {
                $this->xmlwriter->full_tag($field, $value);
            }
        }

        return $data;
    }
1215057
public function on_course_section_end() {

        // migrate files embedded into the section summary field
        $contextid = $this->converter->get_contextid(CONTEXT_COURSE);
        $fileman = $this->converter->get_file_manager($contextid, 'course', 'section', $this->currentsection['id']);
        $this->currentsection['summary'] = moodle1_converter::migrate_referenced_files($this->currentsection['summary'], $fileman);

        // write section's inforef.xml with the file references
        $this->open_xml_writer('sections/section_' . $this->currentsection['id'] . '/inforef.xml');
        $this->xmlwriter->begin_tag('inforef');
        $this->xmlwriter->begin_tag('fileref');
        $fileids = $fileman->get_fileids();
        if (is_array($fileids)) {
            foreach ($fileids as $fileid) {
                $this->write_xml('file', array('id' => $fileid));
            }
        }
        $this->xmlwriter->end_tag('fileref');
        $this->xmlwriter->end_tag('inforef');
        $this->close_xml_writer();

        // stash the section info and write section.xml
        $this->converter->set_stash('sectioninfo', $this->currentsection, $this->currentsection['id']);
        $this->open_xml_writer('sections/section_' . $this->currentsection['id'] . '/section.xml');
        $this->write_xml('section', $this->currentsection);
        $this->close_xml_writer();
        unset($this->currentsection);
    }
585585
function runModule(module, str, replacements) {
    var pattern = module.pattern,
        replace = module.replace,
        match;

    // Reset the pattern so we can re-use it
    pattern.lastIndex = 0;

    while ((match = pattern.exec(str)) !== null) {
        replacements[match.index] = {
            oldStr: match[0],
            newStr: typeof replace === "function"? replace(match) : replace
        };
        if (pattern.global === false) {
            // if the search isn't global we need to break manually
            // because pattern.exec() will always return something
            break;
        }
    }
}
842438
public function cancel_process() {
        global $PAGE;
        // Determine the appropriate URL to redirect the user to.
        if ($PAGE->context->contextlevel == CONTEXT_MODULE && $PAGE->cm !== null) {
            $relevanturl = new moodle_url('/mod/'.$PAGE->cm->modname.'/view.php', array('id' => $PAGE->cm->id));
        } else {
            $relevanturl = new moodle_url('/course/view.php', array('id' => $PAGE->course->id));
        }
        redirect($relevanturl);
    }
441352
public function execute() {
        global $CFG, $DB;

        if (empty($CFG->notifyloginfailures)) {
            return;
        }

        $recip = get_users_from_config($CFG->notifyloginfailures, 'moodle/site:config');

        // Do not look back more than 1 month to avoid crashes due to huge number of records.
        $maximumlastnotifytime = time() - self::NOTIFY_MAXIMUM_TIME;
        if (empty($CFG->lastnotifyfailure) || ($CFG->lastnotifyfailure < $maximumlastnotifytime)) {
            $CFG->lastnotifyfailure = $maximumlastnotifytime;
        }

        // If it has been less than an hour, or if there are no recipients, don't execute.
        if (((time() - HOURSECS) < $CFG->lastnotifyfailure) || !is_array($recip) || count($recip) <= 0) {
            return;
        }

        // We need to deal with the threshold stuff first.
        if (empty($CFG->notifyloginthreshold)) {
            $CFG->notifyloginthreshold = 10; // Default to something sensible.
        }

        // Get all the IPs with more than notifyloginthreshold failures since lastnotifyfailure
        // and insert them into the cache_flags temp table.
        $logmang = get_log_manager();
        $readers = $logmang->get_readers('\core\log\sql_internal_table_reader');
        $reader = reset($readers);
        $readername = key($readers);
        if (empty($reader) || empty($readername)) {
            // No readers, no processing.
            return true;
        }
        $logtable = $reader->get_internal_log_table_name();

        $sql = "SELECT ip, COUNT(*)
                  FROM {" . $logtable . "}
                 WHERE eventname = ?
                       AND timecreated > ?
               GROUP BY ip
                 HAVING COUNT(*) >= ?";
        $params = array('\core\event\user_login_failed', $CFG->lastnotifyfailure, $CFG->notifyloginthreshold);
        $rs = $DB->get_recordset_sql($sql, $params);
        foreach ($rs as $iprec) {
            if (!empty($iprec->ip)) {
                set_cache_flag('login_failure_by_ip', $iprec->ip, '1', 0);
            }
        }
        $rs->close();

        // Get all the INFOs with more than notifyloginthreshold failures since lastnotifyfailure
        // and insert them into the cache_flags temp table.
        $sql = "SELECT userid, count(*)
                  FROM {" . $logtable . "}
                 WHERE eventname = ?
                       AND timecreated > ?
              GROUP BY userid
                HAVING count(*) >= ?";
        $params = array('\core\event\user_login_failed', $CFG->lastnotifyfailure, $CFG->notifyloginthreshold);
        $rs = $DB->get_recordset_sql($sql, $params);
        foreach ($rs as $inforec) {
            if (!empty($inforec->info)) {
                set_cache_flag('login_failure_by_id', $inforec->userid, '1', 0);
            }
        }
        $rs->close();

        // Now, select all the login error logged records belonging to the ips and infos
        // since lastnotifyfailure, that we have stored in the cache_flags table.
        $namefields = get_all_user_name_fields(true, 'u');
        $sql = "SELECT * FROM (
                        SELECT l.*, u.username, $namefields
                          FROM {" . $logtable . "} l
                          JOIN {cache_flags} cf ON l.ip = cf.name
                     LEFT JOIN {user} u         ON l.userid = u.id
                         WHERE l.eventname = ?
                               AND l.timecreated > ?
                               AND cf.flagtype = 'login_failure_by_ip'
                    UNION ALL
                        SELECT l.*, u.username, $namefields
                          FROM {" . $logtable . "} l
                          JOIN {cache_flags} cf ON l.userid = " . $DB->sql_cast_char2int('cf.name') . "
                     LEFT JOIN {user} u         ON l.userid = u.id
                         WHERE l.eventname = ?
                               AND l.timecreated > ?
                               AND cf.flagtype = 'login_failure_by_info') t
             ORDER BY t.timecreated DESC";
        $params = array('\core\event\user_login_failed', $CFG->lastnotifyfailure, '\core\event\user_login_failed', $CFG->lastnotifyfailure);

        // Init some variables.
        $count = 0;
        $messages = '';
        // Iterate over the logs recordset.
        $rs = $DB->get_recordset_sql($sql, $params);
        foreach ($rs as $log) {
            $a = new \stdClass();
            $a->time = userdate($log->timecreated);
            if (empty($log->username)) {
                // Entries with no valid username. We get attempted username from the event's other field.
                $other = \tool_log\helper\reader::decode_other($log->other);
                $a->info = empty($other['username']) ? '' : $other['username'];
                $a->name = get_string('unknownuser');
            } else {
                $a->info = $log->username;
                $a->name = fullname($log);
            }
            $a->ip = $log->ip;
            $messages .= get_string('notifyloginfailuresmessage', '', $a)."\n";
            $count++;
        }
        $rs->close();

        // If we have something useful to report.
        if ($count > 0) {
            $site = get_site();
            $subject = get_string('notifyloginfailuressubject', '', format_string($site->fullname));
            // Calculate the complete body of notification (start + messages + end).
            $params = array('id' => 0, 'modid' => 'site_errors', 'chooselog' => '1', 'logreader' => $readername);
            $url = new \moodle_url('/report/log/index.php', $params);
            $body = get_string('notifyloginfailuresmessagestart', '', $CFG->wwwroot) .
                    (($CFG->lastnotifyfailure != 0) ? '('.userdate($CFG->lastnotifyfailure).')' : '')."\n\n" .
                    $messages .
                    "\n\n".get_string('notifyloginfailuresmessageend', '',  $url->out(false).' ')."\n\n";

            // For each destination, send mail.
            mtrace('Emailing admins about '. $count .' failed login attempts');
            foreach ($recip as $admin) {
                // Emailing the admins directly rather than putting these through the messaging system.
                email_to_user($admin, \core_user::get_noreply_user(), $subject, $body);
            }
        }

        // Update lastnotifyfailure with current time.
        set_config('lastnotifyfailure', time());

        // Finally, delete all the temp records we have created in cache_flags.
        $DB->delete_records_select('cache_flags', "flagtype IN ('login_failure_by_ip', 'login_failure_by_info')");

    }
330572
function resetModule() {
            function resetTernServer() {
                if (_ternNodeDomain.ready()) {
                    _ternNodeDomain.exec('resetTernServer');
                }
            }
            
            if (_ternNodeDomain) {
                if (addFilesPromise) {
                    // If we're in the middle of added files, don't reset 
                    // until we're done
                    addFilesPromise.done(resetTernServer).fail(resetTernServer);
                } else {
                    resetTernServer();
                }
            }
        }
1319853
public function build() {
        global $CFG;

        // Set the backup::VAR_CONTEXTID setting to course context as far as next steps require that
        $coursectxid = context_course::instance($this->get_courseid())->id;
        $this->add_setting(new backup_activity_generic_setting(backup::VAR_CONTEXTID, base_setting::IS_INTEGER, $coursectxid));

        // Set the backup::VAR_COURSEID setting to course, we'll need that in some steps
        $courseid = $this->get_courseid();
        $this->add_setting(new backup_activity_generic_setting(backup::VAR_COURSEID, base_setting::IS_INTEGER, $courseid));

        // Generate the groups file with the final annotated groups and groupings
        // including membership based on setting
        $this->add_step(new backup_groups_structure_step('groups', 'groups.xml'));

        // Generate the questions file with the final annotated question_categories
        $this->add_step(new backup_questions_structure_step('questions', 'questions.xml'));

        // Annotate all the question files for the already annotated question
        // categories (this is performed here and not in the structure step because
        // it involves multiple contexts and as far as we are always backup-ing
        // complete question banks we don't need to restrict at all and can be
        // done in a single pass
        $this->add_step(new backup_annotate_all_question_files('question_files'));

        // Annotate all the user files (conditionally) (profile and icon files)
        // Because each user has its own context, we need a separate/specialised step here
        // This step also ensures that the contexts for all the users exist, so next
        // step can be safely executed (join between users and contexts)
        // Not executed if backup is without users of anonymized
        if ($this->get_setting_value('users') && !$this->get_setting_value('anonymize')) {
            $this->add_step(new backup_annotate_all_user_files('user_files'));
        }

        // Generate the users file (conditionally) with the final annotated users
        // including custom profile fields, preferences, tags, role assignments and
        // overrides
        if ($this->get_setting_value('users')) {
            $this->add_step(new backup_users_structure_step('users', 'users.xml'));
        }

        // Generate the top roles file with all the final annotated roles
        // that have been detected along the whole process. It's just
        // the list of role definitions (no assignments nor permissions)
        $this->add_step(new backup_final_roles_structure_step('roleslist', 'roles.xml'));

        // Generate the gradebook file with categories and course grade items. Do it conditionally, using
        // execute_condition() so only will be excuted if ALL module grade_items in course have been exported
        $this->add_step(new backup_gradebook_structure_step('course_gradebook','gradebook.xml'));

        // Generate the grade history file, conditionally.
        $this->add_step(new backup_grade_history_structure_step('course_grade_history','grade_history.xml'));

        // Generate the course completion
        $this->add_step(new backup_course_completion_structure_step('course_completion', 'completion.xml'));

        // Conditionally generate the badges file.
        if ($this->get_setting_value('badges')) {
            $this->add_step(new backup_badges_structure_step('course_badges', 'badges.xml'));
        }

        // Generate the scales file with all the (final) annotated scales
        $this->add_step(new backup_final_scales_structure_step('scaleslist', 'scales.xml'));

        // Generate the outcomes file with all the (final) annotated outcomes
        $this->add_step(new backup_final_outcomes_structure_step('outcomeslist', 'outcomes.xml'));

        // Migrate the pending annotations to final (prev steps may have added some files)
        // This must be executed before backup files
        $this->add_step(new move_inforef_annotations_to_final('migrate_inforef'));

        // Generate the files.xml file with all the (final) annotated files. At the same
        // time copy all the files from moodle storage to backup storage (uses custom
        // backup_nested_element for that)
        $this->add_step(new backup_final_files_structure_step('fileslist', 'files.xml'));

        // Write the main moodle_backup.xml file, with all the information related
        // to the backup, settings, license, versions and other useful information
        $this->add_step(new backup_main_structure_step('mainfile', 'moodle_backup.xml'));

        require_once($CFG->dirroot . '/backup/util/helper/convert_helper.class.php');

        // Look for converter steps only in type course and mode general backup operations.
        $conversion = false;
        if ($this->plan->get_type() == backup::TYPE_1COURSE and $this->plan->get_mode() == backup::MODE_GENERAL) {
            $converters = convert_helper::available_converters(false);
            foreach ($converters as $value) {
                if ($this->get_setting_value($value)) {
                    // Zip class.
                    $zip_contents      = "{$value}_zip_contents";
                    $store_backup_file = "{$value}_store_backup_file";
                    $convert           = "{$value}_backup_convert";

                    $this->add_step(new $convert("package_convert_{$value}"));
                    $this->add_step(new $zip_contents("zip_contents_{$value}"));
                    $this->add_step(new $store_backup_file("save_backupfile_{$value}"));
                    if (!$conversion) {
                        $conversion = true;
                    }
                }
            }
        }

        // On backup::MODE_IMPORT, we don't have to zip nor store the the file, skip these steps
        if (($this->plan->get_mode() != backup::MODE_IMPORT) && !$conversion) {
            // Generate the zip file (mbz extension)
            $this->add_step(new backup_zip_contents('zip_contents'));

            // Copy the generated zip (.mbz) file to final destination
            $this->add_step(new backup_store_backup_file('save_backupfile'));
        }

        // Clean the temp dir (conditionally) and drop temp tables
        $cleanstep = new drop_and_clean_temp_stuff('drop_and_clean_temp_stuff');
        // Decide about to delete the temp dir (based on backup::MODE_IMPORT)
        $cleanstep->skip_cleaning_temp_dir($this->plan->get_mode() == backup::MODE_IMPORT);
        $this->add_step($cleanstep);

        $this->built = true;
    }