first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+303
View File
@@ -0,0 +1,303 @@
<?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/>.
/**
* Provides support for the conversion of moodle1 backup to the moodle2 format
*
* @package mod_lesson
* @copyright 2011 Rossiani Wijaya <rwijaya@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Lesson conversion handler
*/
class moodle1_mod_lesson_handler extends moodle1_mod_handler {
// @var array of answers, when there are more that 4 answers, we need to fix <jumpto>.
protected $answers;
// @var stdClass a page object of the current page
protected $page;
// @var array of page objects to store entire pages, to help generate nextpageid and prevpageid in data
protected $pages;
// @var int a page id (previous)
protected $prevpageid = 0;
/** @var moodle1_file_manager */
protected $fileman = null;
/** @var int cmid */
protected $moduleid = null;
/**
* Declare the paths in moodle.xml we are able to convert
*
* The method returns list of {@link convert_path} instances.
* For each path returned, the corresponding conversion method must be
* defined.
*
* Note that the path /MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON does not
* actually exist in the file. The last element with the module name was
* appended by the moodle1_converter class.
*
* @return array of {@link convert_path} instances
*/
public function get_paths() {
return array(
new convert_path(
'lesson', '/MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON',
array(
'renamefields' => array(
'usegrademax' => 'usemaxgrade',
),
)
),
new convert_path(
'lesson_page', '/MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES/PAGE',
array(
'newfields' => array(
'contentsformat' => FORMAT_MOODLE,
'nextpageid' => 0, //set to default to the next sequencial page in process_lesson_page()
'prevpageid' => 0
),
)
),
new convert_path(
'lesson_pages', '/MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES'
),
new convert_path(
'lesson_answer', '/MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES/PAGE/ANSWERS/ANSWER',
array(
'newfields' => array(
'answerformat' => 0,
'responseformat' => 0,
),
'renamefields' => array(
'answertext' => 'answer_text',
),
)
)
);
}
/**
* This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON
* data available
*/
public function process_lesson($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_lesson');
// migrate referenced local media files
if (!empty($data['mediafile']) and strpos($data['mediafile'], '://') === false) {
$this->fileman->filearea = 'mediafile';
$this->fileman->itemid = 0;
try {
$this->fileman->migrate_file('course_files/'.$data['mediafile']);
} catch (moodle1_convert_exception $e) {
// the file probably does not exist
$this->log('error migrating lesson mediafile', backup::LOG_WARNING, 'course_files/'.$data['mediafile']);
}
}
// start writing lesson.xml
$this->open_xml_writer("activities/lesson_{$this->moduleid}/lesson.xml");
$this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
'modulename' => 'lesson', 'contextid' => $contextid));
$this->xmlwriter->begin_tag('lesson', array('id' => $instanceid));
foreach ($data as $field => $value) {
if ($field <> 'id') {
$this->xmlwriter->full_tag($field, $value);
}
}
return $data;
}
public function on_lesson_pages_start() {
$this->xmlwriter->begin_tag('pages');
}
/**
* This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES/PAGE
* data available
*/
public function process_lesson_page($data) {
global $CFG;
// replay the upgrade step 2009120801
if ($CFG->texteditors !== 'textarea') {
$data['contents'] = text_to_html($data['contents'], false, false, true);
$data['contentsformat'] = FORMAT_HTML;
}
// store page in pages
$this->page = new stdClass();
$this->page->id = $data['pageid'];
unset($data['pageid']);
$this->page->data = $data;
}
/**
* This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES/PAGE/ANSWERS/ANSWER
* data available
*/
public function process_lesson_answer($data) {
// replay the upgrade step 2010072003
$flags = intval($data['flags']);
if ($flags & 1) {
$data['answer_text'] = text_to_html($data['answer_text'], false, false, true);
$data['answerformat'] = FORMAT_HTML;
}
if ($flags & 2) {
$data['response'] = text_to_html($data['response'], false, false, true);
$data['responseformat'] = FORMAT_HTML;
}
// buffer for conversion of <jumpto> in line with
// upgrade step 2010121400 from mod/lesson/db/upgrade.php
$this->answers[] = $data;
}
public function on_lesson_page_end() {
$this->page->answers = $this->answers;
$this->pages[] = $this->page;
$firstbatch = count($this->pages) > 2;
$nextbatch = count($this->pages) > 1 && $this->prevpageid != 0;
if ( $firstbatch || $nextbatch ) { //we can write out 1 page atleast
if ($this->prevpageid == 0) {
// start writing with n-2 page (relative to this on_lesson_page_end() call)
$pg1 = $this->pages[1];
$pg0 = $this->pages[0];
$this->write_single_page_xml($pg0, 0, $pg1->id);
$this->prevpageid = $pg0->id;
array_shift($this->pages); //bye bye page0
}
$pg1 = $this->pages[0];
// write pg1 referencing prevpageid and pg2
$pg2 = $this->pages[1];
$this->write_single_page_xml($pg1, $this->prevpageid, $pg2->id);
$this->prevpageid = $pg1->id;
array_shift($this->pages); //throw written n-1th page
}
$this->answers = array(); //clear answers for the page ending. do not unset, object property will be missing.
$this->page = null;
}
public function on_lesson_pages_end() {
if ($this->pages) {
if (isset($this->pages[1])) { // write the case of only 2 pages.
$this->write_single_page_xml($this->pages[0], $this->prevpageid, $this->pages[1]->id);
$this->prevpageid = $this->pages[0]->id;
array_shift($this->pages);
}
//write the remaining (first/last) single page
$this->write_single_page_xml($this->pages[0], $this->prevpageid, 0);
}
$this->xmlwriter->end_tag('pages');
//reset
unset($this->pages);
$this->prevpageid = 0;
}
/**
* This is executed when we reach the closing </MOD> tag of our 'lesson' path
*/
public function on_lesson_end() {
// Append empty <overrides> subpath element.
$this->write_xml('overrides', array());
// finish writing lesson.xml
$this->xmlwriter->end_tag('lesson');
$this->xmlwriter->end_tag('activity');
$this->close_xml_writer();
// write inforef.xml
$this->open_xml_writer("activities/lesson_{$this->moduleid}/inforef.xml");
$this->xmlwriter->begin_tag('inforef');
$this->xmlwriter->begin_tag('fileref');
foreach ($this->fileman->get_fileids() as $fileid) {
$this->write_xml('file', array('id' => $fileid));
}
$this->xmlwriter->end_tag('fileref');
$this->xmlwriter->end_tag('inforef');
$this->close_xml_writer();
}
/**
* writes out the given page into the open xml handle
* @param type $page
* @param type $prevpageid
* @param type $nextpageid
*/
protected function write_single_page_xml($page, $prevpageid=0, $nextpageid=0) {
//mince nextpageid and prevpageid
$page->data['nextpageid'] = $nextpageid;
$page->data['prevpageid'] = $prevpageid;
// write out each page data
$this->xmlwriter->begin_tag('page', array('id' => $page->id));
foreach ($page->data as $field => $value) {
$this->xmlwriter->full_tag($field, $value);
}
//effectively on_lesson_answers_end(), where we write out answers for current page.
$answers = $page->answers;
$this->xmlwriter->begin_tag('answers');
$numanswers = $answers ? count($answers) : 0;
if ($numanswers) { //if there are any answers (possible there are none!)
if ($numanswers > 3 && $page->data['qtype'] == 5) { //fix only jumpto only for matching question types.
if ($answers[0]['jumpto'] !== '0' || $answers[1]['jumpto'] !== '0') {
if ($answers[2]['jumpto'] !== '0') {
$answers[0]['jumpto'] = $answers[2]['jumpto'];
$answers[2]['jumpto'] = '0';
}
if ($answers[3]['jumpto'] !== '0') {
$answers[1]['jumpto'] = $answers[3]['jumpto'];
$answers[3]['jumpto'] = '0';
}
}
}
foreach ($answers as $data) {
$this->write_xml('answer', $data, array('/answer/id'));
}
}
$this->xmlwriter->end_tag('answers');
// answers is now closed for current page. Ending the page.
$this->xmlwriter->end_tag('page');
}
}
@@ -0,0 +1,106 @@
<?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/>.
/**
* This file contains the backup task for the lesson module
*
* @package mod_lesson
* @category backup
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/lesson/backup/moodle2/backup_lesson_stepslib.php');
/**
* Provides the steps to perform one complete backup of the Lesson instance
*
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_lesson_activity_task extends backup_activity_task {
/**
* No specific settings for this activity
*/
protected function define_my_settings() {
}
/**
* Defines a backup step to store the instance data in the lesson.xml file
*/
protected function define_my_steps() {
$this->add_step(new backup_lesson_activity_structure_step('lesson structure', 'lesson.xml'));
}
/**
* Encodes URLs to various Lesson scripts
*
* @param string $content some HTML text that eventually contains URLs to the activity instance scripts
* @return string the content with the URLs encoded
*/
public static function encode_content_links($content) {
global $CFG;
$base = preg_quote($CFG->wwwroot.'/mod/lesson','#');
// Provides the interface for overall authoring of lessons
$pattern = '#'.$base.'/edit\.php\?id=([0-9]+)#';
$replacement = '$@LESSONEDIT*$1@$';
$content = preg_replace($pattern, $replacement, $content);
// Action for adding a question page. Prints an HTML form.
$pattern = '#'.$base.'/editpage\.php\?id=([0-9]+)&(amp;)?pageid=([0-9]+)#';
$replacement = '$@LESSONEDITPAGE*$1*$3@$';
$content = preg_replace($pattern, $replacement, $content);
// Provides the interface for grading essay questions
$pattern = '#'.$base.'/essay\.php\?id=([0-9]+)#';
$replacement = '$@LESSONESSAY*$1@$';
$content = preg_replace($pattern, $replacement, $content);
// Provides the interface for viewing the report
$pattern = '#'.$base.'/report\.php\?id=([0-9]+)#';
$replacement = '$@LESSONREPORT*$1@$';
$content = preg_replace($pattern, $replacement, $content);
// This file plays the mediafile set in lesson settings.
$pattern = '#'.$base.'/mediafile\.php\?id=([0-9]+)#';
$replacement = '$@LESSONMEDIAFILE*$1@$';
$content = preg_replace($pattern, $replacement, $content);
// This page lists all the instances of lesson in a particular course
$pattern = '#'.$base.'/index\.php\?id=([0-9]+)#';
$replacement = '$@LESSONINDEX*$1@$';
$content = preg_replace($pattern, $replacement, $content);
// This page prints a particular page of lesson
$pattern = '#'.$base.'/view\.php\?id=([0-9]+)&(amp;)?pageid=([0-9]+)#';
$replacement = '$@LESSONVIEWPAGE*$1*$3@$';
$content = preg_replace($pattern, $replacement, $content);
// Link to one lesson by cmid
$pattern = '#'.$base.'/view\.php\?id=([0-9]+)#';
$replacement = '$@LESSONVIEWBYID*$1@$';
$content = preg_replace($pattern, $replacement, $content);
// Return the now encoded content
return $content;
}
}
@@ -0,0 +1,211 @@
<?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/>.
/**
* This file contains the backup structure for the lesson module
*
* This is the "graphical" structure of the lesson module:
*
* lesson ---------->-------------|------------>---------|----------->----------|
* (CL,pk->id) | | |
* | | | |
* | lesson_grades lesson_timer lesson_overrides
* | (UL, pk->id,fk->lessonid) (UL, pk->id,fk->lessonid) (UL, pk->id,fk->lessonid)
* | |
* | |
* | |
* | |
* lesson_pages-------->-------lesson_branch
* (CL,pk->id,fk->lessonid) (UL, pk->id,fk->pageid)
* |
* |
* |
* lesson_answers
* (CL,pk->id,fk->pageid)
* |
* |
* |
* lesson_attempts
* (UL,pk->id,fk->answerid)
*
* Meaning: pk->primary key field of the table
* fk->foreign key to link with parent
* nt->nested field (recursive data)
* CL->course level info
* UL->user level info
* files->table may have files)
*
* @package mod_lesson
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Structure step class that informs a backup task how to backup the lesson module.
*
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_lesson_activity_structure_step extends backup_activity_structure_step {
protected function define_structure() {
// The lesson table
// This table contains all of the goodness for the lesson module, quite
// alot goes into it but nothing relational other than course when will
// need to be corrected upon restore.
$lesson = new backup_nested_element('lesson', array('id'), array(
'course', 'name', 'intro', 'introformat', 'practice', 'modattempts',
'usepassword', 'password',
'dependency', 'conditions', 'grade', 'custom', 'ongoing', 'usemaxgrade',
'maxanswers', 'maxattempts', 'review', 'nextpagedefault', 'feedback',
'minquestions', 'maxpages', 'timelimit', 'retake', 'activitylink',
'mediafile', 'mediaheight', 'mediawidth', 'mediaclose', 'slideshow',
'width', 'height', 'bgcolor', 'displayleft', 'displayleftif', 'progressbar',
'available', 'deadline', 'timemodified',
'completionendreached', 'completiontimespent', 'allowofflineattempts'
));
// The lesson_pages table
// Grouped within a `pages` element, important to note that page is relational
// to the lesson, and also to the previous/next page in the series.
// Upon restore prevpageid and nextpageid will need to be corrected.
$pages = new backup_nested_element('pages');
$page = new backup_nested_element('page', array('id'), array(
'prevpageid','nextpageid','qtype','qoption','layout',
'display','timecreated','timemodified','title','contents',
'contentsformat'
));
// The lesson_answers table
// Grouped within an answers `element`, the lesson_answers table relates
// to the page and lesson with `pageid` and `lessonid` that will both need
// to be corrected during restore.
$answers = new backup_nested_element('answers');
$answer = new backup_nested_element('answer', array('id'), array(
'jumpto','grade','score','flags','timecreated','timemodified','answer_text',
'response', 'answerformat', 'responseformat'
));
// Tell the answer element about the answer_text elements mapping to the answer
// database field.
$answer->set_source_alias('answer', 'answer_text');
// The lesson_attempts table
// Grouped by an `attempts` element this is relational to the page, lesson,
// and user.
$attempts = new backup_nested_element('attempts');
$attempt = new backup_nested_element('attempt', array('id'), array(
'userid','retry','correct','useranswer','timeseen'
));
// The lesson_branch table
// Grouped by a `branch` element this is relational to the page, lesson,
// and user.
$branches = new backup_nested_element('branches');
$branch = new backup_nested_element('branch', array('id'), array(
'userid', 'retry', 'flag', 'timeseen', 'nextpageid'
));
// The lesson_grades table
// Grouped by a grades element this is relational to the lesson and user.
$grades = new backup_nested_element('grades');
$grade = new backup_nested_element('grade', array('id'), array(
'userid','grade','late','completed'
));
// The lesson_timer table
// Grouped by a `timers` element this is relational to the lesson and user.
$timers = new backup_nested_element('timers');
$timer = new backup_nested_element('timer', array('id'), array(
'userid', 'starttime', 'lessontime', 'completed', 'timemodifiedoffline'
));
$overrides = new backup_nested_element('overrides');
$override = new backup_nested_element('override', array('id'), array(
'groupid', 'userid', 'available', 'deadline', 'timelimit',
'review', 'maxattempts', 'retake', 'password'));
// Now that we have all of the elements created we've got to put them
// together correctly.
$lesson->add_child($pages);
$pages->add_child($page);
$page->add_child($answers);
$answers->add_child($answer);
$answer->add_child($attempts);
$attempts->add_child($attempt);
$page->add_child($branches);
$branches->add_child($branch);
$lesson->add_child($grades);
$grades->add_child($grade);
$lesson->add_child($timers);
$timers->add_child($timer);
$lesson->add_child($overrides);
$overrides->add_child($override);
// Set the source table for the elements that aren't reliant on the user
// at this point (lesson, lesson_pages, lesson_answers)
$lesson->set_source_table('lesson', array('id' => backup::VAR_ACTIVITYID));
//we use SQL here as it must be ordered by prevpageid so that restore gets the pages in the right order.
$page->set_source_table('lesson_pages', array('lessonid' => backup::VAR_PARENTID), 'prevpageid ASC');
// We use SQL here as answers must be ordered by id so that the restore gets them in the right order
$answer->set_source_table('lesson_answers', array('pageid' => backup::VAR_PARENTID), 'id ASC');
// Lesson overrides to backup are different depending of user info.
$overrideparams = array('lessonid' => backup::VAR_PARENTID);
// Check if we are also backing up user information
if ($this->get_setting_value('userinfo')) {
// Set the source table for elements that are reliant on the user
// lesson_attempts, lesson_branch, lesson_grades, lesson_timer.
$attempt->set_source_table('lesson_attempts', array('answerid' => backup::VAR_PARENTID));
$branch->set_source_table('lesson_branch', array('pageid' => backup::VAR_PARENTID));
$grade->set_source_table('lesson_grades', array('lessonid'=>backup::VAR_PARENTID));
$timer->set_source_table('lesson_timer', array('lessonid' => backup::VAR_PARENTID));
} else {
$overrideparams['userid'] = backup_helper::is_sqlparam(null); // Without userinfo, skip user overrides.
}
// Skip group overrides if not including groups.
$groupinfo = $this->get_setting_value('groups');
if (!$groupinfo) {
$overrideparams['groupid'] = backup_helper::is_sqlparam(null);
}
$override->set_source_table('lesson_overrides', $overrideparams);
// Annotate the user id's where required.
$attempt->annotate_ids('user', 'userid');
$branch->annotate_ids('user', 'userid');
$grade->annotate_ids('user', 'userid');
$timer->annotate_ids('user', 'userid');
$override->annotate_ids('user', 'userid');
$override->annotate_ids('group', 'groupid');
// Annotate the file areas in user by the lesson module.
$lesson->annotate_files('mod_lesson', 'intro', null);
$lesson->annotate_files('mod_lesson', 'mediafile', null);
$page->annotate_files('mod_lesson', 'page_contents', 'id');
$answer->annotate_files('mod_lesson', 'page_answers', 'id');
$answer->annotate_files('mod_lesson', 'page_responses', 'id');
$attempt->annotate_files('mod_lesson', 'essay_responses', 'id');
$attempt->annotate_files('mod_lesson', 'essay_answers', 'id');
// Prepare and return the structure we have just created for the lesson module.
return $this->prepare_activity_structure($lesson);
}
}
@@ -0,0 +1,161 @@
<?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/>.
/**
* @package mod_lesson
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/lesson/backup/moodle2/restore_lesson_stepslib.php'); // Because it exists (must)
/**
* lesson restore task that provides all the settings and steps to perform one
* complete restore of the activity
*/
class restore_lesson_activity_task extends restore_activity_task {
/**
* Define (add) particular settings this activity can have
*/
protected function define_my_settings() {
// No particular settings for this activity
}
/**
* Define (add) particular steps this activity can have
*/
protected function define_my_steps() {
// lesson only has one structure step
$this->add_step(new restore_lesson_activity_structure_step('lesson_structure', 'lesson.xml'));
}
/**
* Define the contents in the activity that must be
* processed by the link decoder
*/
public static function define_decode_contents() {
$contents = array();
$contents[] = new restore_decode_content('lesson', array('intro'), 'lesson');
$contents[] = new restore_decode_content('lesson_pages', array('contents'), 'lesson_page');
$contents[] = new restore_decode_content('lesson_answers', array('answer', 'response'), 'lesson_answer');
return $contents;
}
/**
* Define the decoding rules for links belonging
* to the activity to be executed by the link decoder
*/
public static function define_decode_rules() {
$rules = array();
$rules[] = new restore_decode_rule('LESSONEDIT', '/mod/lesson/edit.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('LESSONESAY', '/mod/lesson/essay.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('LESSONREPORT', '/mod/lesson/report.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('LESSONMEDIAFILE', '/mod/lesson/mediafile.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('LESSONVIEWBYID', '/mod/lesson/view.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('LESSONINDEX', '/mod/lesson/index.php?id=$1', 'course');
$rules[] = new restore_decode_rule('LESSONVIEWPAGE', '/mod/lesson/view.php?id=$1&pageid=$2', array('course_module', 'lesson_page'));
$rules[] = new restore_decode_rule('LESSONEDITPAGE', '/mod/lesson/edit.php?id=$1&pageid=$2', array('course_module', 'lesson_page'));
return $rules;
}
/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* lesson logs. It must return one array
* of {@link restore_log_rule} objects
*/
public static function define_restore_log_rules() {
$rules = array();
$rules[] = new restore_log_rule('lesson', 'add', 'view.php?id={course_module}', '{lesson}');
$rules[] = new restore_log_rule('lesson', 'update', 'view.php?id={course_module}', '{lesson}');
$rules[] = new restore_log_rule('lesson', 'view', 'view.php?id={course_module}', '{lesson}');
$rules[] = new restore_log_rule('lesson', 'start', 'view.php?id={course_module}', '{lesson}');
$rules[] = new restore_log_rule('lesson', 'end', 'view.php?id={course_module}', '{lesson}');
$rules[] = new restore_log_rule('lesson', 'view grade', 'essay.php?id={course_module}', '[name]');
$rules[] = new restore_log_rule('lesson', 'update grade', 'essay.php?id={course_module}', '[name]');
$rules[] = new restore_log_rule('lesson', 'update email essay grade', 'essay.php?id={course_module}', '[name]');
return $rules;
}
/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* course logs. It must return one array
* of {@link restore_log_rule} objects
*
* Note this rules are applied when restoring course logs
* by the restore final task, but are defined here at
* activity level. All them are rules not linked to any module instance (cmid = 0)
*/
public static function define_restore_log_rules_for_course() {
$rules = array();
$rules[] = new restore_log_rule('lesson', 'view all', 'index.php?id={course}', null);
return $rules;
}
/**
* Re-map the dependency and activitylink information
* If a depency or activitylink has no mapping in the backup data then it could either be a duplication of a
* lesson, or a backup/restore of a single lesson. We have no way to determine which and whether this is the
* same site and/or course. Therefore we try and retrieve a mapping, but fallback to the original value if one
* was not found. We then test to see whether the value found is valid for the course being restored into.
*/
public function after_restore() {
global $DB;
$lesson = $DB->get_record('lesson', array('id' => $this->get_activityid()), 'id, course, dependency, activitylink');
$updaterequired = false;
if (!empty($lesson->dependency)) {
$updaterequired = true;
if ($newitem = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'lesson', $lesson->dependency)) {
$lesson->dependency = $newitem->newitemid;
}
if (!$DB->record_exists('lesson', array('id' => $lesson->dependency, 'course' => $lesson->course))) {
$lesson->dependency = 0;
}
}
if (!empty($lesson->activitylink)) {
$updaterequired = true;
if ($newitem = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'course_module', $lesson->activitylink)) {
$lesson->activitylink = $newitem->newitemid;
}
if (!$DB->record_exists('course_modules', array('id' => $lesson->activitylink, 'course' => $lesson->course))) {
$lesson->activitylink = 0;
}
}
if ($updaterequired) {
$DB->update_record('lesson', $lesson);
}
}
}
@@ -0,0 +1,332 @@
<?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/>.
/**
* @package mod_lesson
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Define all the restore steps that will be used by the restore_lesson_activity_task
*/
/**
* Structure step to restore one lesson activity
*/
class restore_lesson_activity_structure_step extends restore_activity_structure_step {
// Store the answers as they're received but only process them at the
// end of the lesson
protected $answers = array();
protected function define_structure() {
$paths = array();
$userinfo = $this->get_setting_value('userinfo');
$paths[] = new restore_path_element('lesson', '/activity/lesson');
$paths[] = new restore_path_element('lesson_page', '/activity/lesson/pages/page');
$paths[] = new restore_path_element('lesson_answer', '/activity/lesson/pages/page/answers/answer');
$paths[] = new restore_path_element('lesson_override', '/activity/lesson/overrides/override');
if ($userinfo) {
$paths[] = new restore_path_element('lesson_attempt', '/activity/lesson/pages/page/answers/answer/attempts/attempt');
$paths[] = new restore_path_element('lesson_grade', '/activity/lesson/grades/grade');
$paths[] = new restore_path_element('lesson_branch', '/activity/lesson/pages/page/branches/branch');
$paths[] = new restore_path_element('lesson_highscore', '/activity/lesson/highscores/highscore');
$paths[] = new restore_path_element('lesson_timer', '/activity/lesson/timers/timer');
}
// Return the paths wrapped into standard activity structure
return $this->prepare_activity_structure($paths);
}
protected function process_lesson($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->course = $this->get_courseid();
// Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
// See MDL-9367.
$data->available = $this->apply_date_offset($data->available);
$data->deadline = $this->apply_date_offset($data->deadline);
// The lesson->highscore code was removed in MDL-49581.
// Remove it if found in the backup file.
if (isset($data->showhighscores)) {
unset($data->showhighscores);
}
if (isset($data->highscores)) {
unset($data->highscores);
}
// Supply items that maybe missing from previous versions.
if (!isset($data->completionendreached)) {
$data->completionendreached = 0;
}
if (!isset($data->completiontimespent)) {
$data->completiontimespent = 0;
}
if (!isset($data->intro)) {
$data->intro = '';
$data->introformat = FORMAT_HTML;
}
// Compatibility with old backups with maxtime and timed fields.
if (!isset($data->timelimit)) {
if (isset($data->timed) && isset($data->maxtime) && $data->timed) {
$data->timelimit = 60 * $data->maxtime;
} else {
$data->timelimit = 0;
}
}
// insert the lesson record
$newitemid = $DB->insert_record('lesson', $data);
// immediately after inserting "activity" record, call this
$this->apply_activity_instance($newitemid);
}
protected function process_lesson_page($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->lessonid = $this->get_new_parentid('lesson');
// We'll remap all the prevpageid and nextpageid at the end, once all pages have been created
$newitemid = $DB->insert_record('lesson_pages', $data);
$this->set_mapping('lesson_page', $oldid, $newitemid, true); // Has related fileareas
}
protected function process_lesson_answer($data) {
global $DB;
$data = (object)$data;
$data->lessonid = $this->get_new_parentid('lesson');
$data->pageid = $this->get_new_parentid('lesson_page');
$data->answer = $data->answer_text;
// Set a dummy mapping to get the old ID so that it can be used by get_old_parentid when
// processing attempts. It will be corrected in after_execute
$this->set_mapping('lesson_answer', $data->id, 0, true); // Has related fileareas.
// Answers need to be processed in order, so we store them in an
// instance variable and insert them in the after_execute stage
$this->answers[$data->id] = $data;
}
protected function process_lesson_attempt($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->lessonid = $this->get_new_parentid('lesson');
$data->pageid = $this->get_new_parentid('lesson_page');
// We use the old answerid here as the answer isn't created until after_execute
$data->answerid = $this->get_old_parentid('lesson_answer');
$data->userid = $this->get_mappingid('user', $data->userid);
$newitemid = $DB->insert_record('lesson_attempts', $data);
$this->set_mapping('lesson_attempt', $oldid, $newitemid, true); // Has related fileareas.
}
protected function process_lesson_grade($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->lessonid = $this->get_new_parentid('lesson');
$data->userid = $this->get_mappingid('user', $data->userid);
$newitemid = $DB->insert_record('lesson_grades', $data);
$this->set_mapping('lesson_grade', $oldid, $newitemid);
}
protected function process_lesson_branch($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->lessonid = $this->get_new_parentid('lesson');
$data->pageid = $this->get_new_parentid('lesson_page');
$data->userid = $this->get_mappingid('user', $data->userid);
$newitemid = $DB->insert_record('lesson_branch', $data);
}
protected function process_lesson_highscore($data) {
// Do not process any high score data.
// high scores were removed in Moodle 3.0 See MDL-49581.
}
protected function process_lesson_timer($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->lessonid = $this->get_new_parentid('lesson');
$data->userid = $this->get_mappingid('user', $data->userid);
// Supply item that maybe missing from previous versions.
if (!isset($data->completed)) {
$data->completed = 0;
}
$newitemid = $DB->insert_record('lesson_timer', $data);
}
/**
* Process a lesson override restore
* @param object $data The data in object form
* @return void
*/
protected function process_lesson_override($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
// Based on userinfo, we'll restore user overides or no.
$userinfo = $this->get_setting_value('userinfo');
// Skip user overrides if we are not restoring userinfo.
if (!$userinfo && !is_null($data->userid)) {
return;
}
$data->lessonid = $this->get_new_parentid('lesson');
if (!is_null($data->userid)) {
$data->userid = $this->get_mappingid('user', $data->userid);
}
if (!is_null($data->groupid)) {
$data->groupid = $this->get_mappingid('group', $data->groupid);
}
// Skip if there is no user and no group data.
if (empty($data->userid) && empty($data->groupid)) {
return;
}
$data->available = $this->apply_date_offset($data->available);
$data->deadline = $this->apply_date_offset($data->deadline);
$newitemid = $DB->insert_record('lesson_overrides', $data);
// Add mapping, restore of logs needs it.
$this->set_mapping('lesson_override', $oldid, $newitemid);
}
protected function after_execute() {
global $DB;
// Answers must be sorted by id to ensure that they're shown correctly
ksort($this->answers);
foreach ($this->answers as $answer) {
$newitemid = $DB->insert_record('lesson_answers', $answer);
$this->set_mapping('lesson_answer', $answer->id, $newitemid, true);
// Update the lesson attempts to use the newly created answerid
$DB->set_field('lesson_attempts', 'answerid', $newitemid, array(
'lessonid' => $answer->lessonid,
'pageid' => $answer->pageid,
'answerid' => $answer->id));
}
// Add lesson files, no need to match by itemname (just internally handled context).
$this->add_related_files('mod_lesson', 'intro', null);
$this->add_related_files('mod_lesson', 'mediafile', null);
// Add lesson page files, by lesson_page itemname
$this->add_related_files('mod_lesson', 'page_contents', 'lesson_page');
$this->add_related_files('mod_lesson', 'page_answers', 'lesson_answer');
$this->add_related_files('mod_lesson', 'page_responses', 'lesson_answer');
$this->add_related_files('mod_lesson', 'essay_responses', 'lesson_attempt');
$this->add_related_files('mod_lesson', 'essay_answers', 'lesson_attempt');
// Remap all the restored prevpageid and nextpageid now that we have all the pages and their mappings
$rs = $DB->get_recordset('lesson_pages', array('lessonid' => $this->task->get_activityid()),
'', 'id, prevpageid, nextpageid');
foreach ($rs as $page) {
$page->prevpageid = (empty($page->prevpageid)) ? 0 : $this->get_mappingid('lesson_page', $page->prevpageid);
$page->nextpageid = (empty($page->nextpageid)) ? 0 : $this->get_mappingid('lesson_page', $page->nextpageid);
$DB->update_record('lesson_pages', $page);
}
$rs->close();
// Remap all the restored 'jumpto' fields now that we have all the pages and their mappings
$rs = $DB->get_recordset('lesson_answers', array('lessonid' => $this->task->get_activityid()),
'', 'id, jumpto');
foreach ($rs as $answer) {
if ($answer->jumpto > 0) {
$answer->jumpto = $this->get_mappingid('lesson_page', $answer->jumpto);
$DB->update_record('lesson_answers', $answer);
}
}
$rs->close();
// Remap all the restored 'nextpageid' fields now that we have all the pages and their mappings.
$rs = $DB->get_recordset('lesson_branch', array('lessonid' => $this->task->get_activityid()),
'', 'id, nextpageid');
foreach ($rs as $answer) {
if ($answer->nextpageid > 0) {
$answer->nextpageid = $this->get_mappingid('lesson_page', $answer->nextpageid);
$DB->update_record('lesson_branch', $answer);
}
}
$rs->close();
// Replay the upgrade step 2015030301
// to clean lesson answers that should be plain text.
// 1 = LESSON_PAGE_SHORTANSWER, 8 = LESSON_PAGE_NUMERICAL, 20 = LESSON_PAGE_BRANCHTABLE.
$sql = 'SELECT a.*
FROM {lesson_answers} a
JOIN {lesson_pages} p ON p.id = a.pageid
WHERE a.answerformat <> :format
AND a.lessonid = :lessonid
AND p.qtype IN (1, 8, 20)';
$badanswers = $DB->get_recordset_sql($sql, array('lessonid' => $this->task->get_activityid(), 'format' => FORMAT_MOODLE));
foreach ($badanswers as $badanswer) {
// Strip tags from answer text and convert back the format to FORMAT_MOODLE.
$badanswer->answer = strip_tags($badanswer->answer);
$badanswer->answerformat = FORMAT_MOODLE;
$DB->update_record('lesson_answers', $badanswer);
}
$badanswers->close();
// Replay the upgrade step 2015032700.
// Delete any orphaned lesson_branch record.
if ($DB->get_dbfamily() === 'mysql') {
$sql = "DELETE {lesson_branch}
FROM {lesson_branch}
LEFT JOIN {lesson_pages}
ON {lesson_branch}.pageid = {lesson_pages}.id
WHERE {lesson_pages}.id IS NULL";
} else {
$sql = "DELETE FROM {lesson_branch}
WHERE NOT EXISTS (
SELECT 'x' FROM {lesson_pages}
WHERE {lesson_branch}.pageid = {lesson_pages}.id)";
}
$DB->execute($sql);
}
}