Skip to content

Instantly share code, notes, and snippets.

@ericmerrill
Last active March 29, 2021 19:20
Show Gist options
  • Select an option

  • Save ericmerrill/e5f9ad3578cd40a980021d2be882a851 to your computer and use it in GitHub Desktop.

Select an option

Save ericmerrill/e5f9ad3578cd40a980021d2be882a851 to your computer and use it in GitHub Desktop.
A file to backup calendar data out of a old Moodle copy and into a new one to fix issues raised in MDL-71156
<?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/>.
/**
* Backup and restore calendar IDs to fix dataloss reported in MDL-71156.
*
* USE AT YOUR OWN RISK!
*
* Expects to be in admin/cli, although just modify the require line for
* config.php if you want to change that.
*
* @copyright 2021 Eric Merrill <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require(__DIR__.'/../../config.php');
require_once("$CFG->libdir/clilib.php");
$longparams = [
'backup' => null,
'help' => false,
'restorefile' => false,
'modulename' => false
];
$shortmappings = [
'b' => 'backup',
'h' => 'help',
'f' => 'restorefile'
];
// Get CLI params.
list($options, $unrecognized) = cli_get_params($longparams, $shortmappings);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if (empty($options['help']) && empty($options['backup']) && empty($options['restorefile'])) {
mtrace("--backup or --restorefile flag must be set");
$options['help'] = true;
}
if ($options['help']) {
echo "THIS IS NOT AN OFFICIAL MOODLE FILE. USE AT YOUR OWN RISK!
This file has two parts, used to fixup records from the issue reported in MDL-71156, if you have a
live backup of the system.
When used on a backup before the 3.10.2/3.9.5 update with the -b option, it will output rows of data
(rowid, userid). Save that to a file on your post update system.
If you do not have the backup on a live Moodle system that can run PHP code, you need to output from
your backup database a file that has records from mdl_events that match the query:
SELECT id, modulename, userid FROM mdl_event
WHERE (eventtype <> 'user' OR priority <> 0)
AND courseid = 0
AND groupid = 0
AND categoryid = 0
One per line, in the format of:
id,modulename,userid
id,modulename,userid
id,modulename,userid
On the post-update system (with broken records), you will use -f=/path/to/file/above.txt, and it
will read the file, and correct the broken DB records to the best of its ability.
Options:
-b, --backup Output data to be used later by this script on another system
-f, --restorefile=FILEPATH Takes a filepath and reads the contents. Uses the IDs to attempt to correct
calendar records. Works on backup or restore step.
--modulename=MODNAME Limit to the specified modulename
-h, --help Print out this help
Example:
\$ sudo -u www-data /usr/bin/php admin/cli/cal_id_backup_restore.php.php -b > /home/u/user/backupfile.txt
\$ sudo -u www-data /usr/bin/php admin/cli/cal_id_backup_restore.php.php -f=/home/u/user/backupfile.txt
";
die;
}
$modfilter = false;
if ($options['modulename']) {
$modfilter = $options['modulename'];
}
if ($options['backup']) {
$sql = "SELECT id, modulename, userid FROM {event}
WHERE (eventtype <> 'user' OR priority <> 0)
AND courseid = 0
AND groupid = 0
AND categoryid = 0";
$params = [];
if ($modfilter) {
$sql .= ' AND modulename = ?';
$params = [$modfilter];
}
$records = $DB->get_recordset_sql($sql, $params);
foreach ($records as $record) {
mtrace($record->id . ',' . $record->modulename . ',' . $record->userid);
}
$records->close();
} else if ($options['restorefile']) {
$filepath = $options['restorefile'];
if (!is_string($filepath) || !is_readable($filepath)) {
cli_error('Input file cannot be found or is not readable');
}
$fh = fopen($filepath, "r");
if (empty($fh)) {
cli_error('Input file cannot be read');
}
while ($line = fgets($fh)) {
$line = trim($line);
$parts = explode(',', $line);
if (count($parts) != 3) {
mtrace('ERROR: Incorrect number of items in line: ' . $line);
continue;
}
$rowid = trim($parts[0]);
$module = trim(trim($parts[1]), "'\""); // Trim quotes in case they we added on accident.
$userid = trim($parts[2]);
if (!is_numeric($rowid) || !is_numeric($userid) || empty($module)) {
mtrace('ERROR: Incorrectly formatted data in line: ' . $line);
continue;
}
if ($modfilter && $module != $modfilter) {
mtrace("INFO: Skipping line because line doesn't match modulename flag: " . $line);
continue;
}
$row = $DB->get_record('event', ['id' => $rowid]);
if (empty($row)) {
mtrace('INFO: Could not get row for line: ' . $line);
continue;
}
if ($row->userid !== '0') {
if ($row->userid == $userid) {
mtrace('INFO: Row already has expected userid: ' . $line);
continue;
}
mtrace('ERROR: Database row already has a userid and cannot be updated: ' . $line);
continue;
}
if ($row->modulename !== $module) {
mtrace('ERROR: Row\'s modulename doesn\'t match input line: ' . $line);
continue;
}
if ($row->courseid !== '0' || $row->groupid !== '0' || $row->categoryid !== '0') {
mtrace('ERROR: Retrieved record does not have an empty course, group, and/or category: ' . $line);
continue;
}
$DB->set_field('event', 'userid', $userid, ['id' => $row->id]);
mtrace('INFO: Updated userid for row: ' . $line);
}
fclose($fh);
}
@uzum4ki
Copy link

uzum4ki commented Mar 23, 2021

Thanx a lot fot this script!
It helps us to fix our broken records on a quite large install which, unfortunately, has been upgraded last saturday to 3.10.2... so again: thank you very much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment