From 1d8066e2d0a4eec1af9d7c68f1fa6646e4ed03e1 Mon Sep 17 00:00:00 2001 From: Davo Smith Date: Wed, 18 Apr 2012 11:01:30 +0100 Subject: [PATCH] MDL-31484 backup - repeated restores with anonymised users now works correctly --- backup/util/dbops/restore_dbops.class.php | 25 +++++++++++++------ .../helper/backup_anonymizer_helper.class.php | 18 +++++++++++++ backup/util/includes/restore_includes.php | 1 + 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/backup/util/dbops/restore_dbops.class.php b/backup/util/dbops/restore_dbops.class.php index e856ead712c..c4d42d46617 100644 --- a/backup/util/dbops/restore_dbops.class.php +++ b/backup/util/dbops/restore_dbops.class.php @@ -1148,14 +1148,16 @@ abstract class restore_dbops { * * If restoring users from same site backup: * 1A - Normal check: If match by id and username and mnethost => ok, return target user - * 1B - Handle users deleted in DB and "alive" in backup file: + * 1B - If restoring an 'anonymous' user (created via the 'Anonymize user information' option) try to find a + * match by username only => ok, return target user MDL-31484 + * 1C - Handle users deleted in DB and "alive" in backup file: * If match by id and mnethost and user is deleted in DB and * (match by username LIKE 'backup_email.%' or by non empty email = md5(username)) => ok, return target user - * 1C - Handle users deleted in backup file and "alive" in DB: + * 1D - Handle users deleted in backup file and "alive" in DB: * If match by id and mnethost and user is deleted in backup file * and match by email = email_without_time(backup_email) => ok, return target user - * 1D - Conflict: If match by username and mnethost and doesn't match by id => conflict, return false - * 1E - None of the above, return true => User needs to be created + * 1E - Conflict: If match by username and mnethost and doesn't match by id => conflict, return false + * 1F - None of the above, return true => User needs to be created * * if restoring from another site backup (cannot match by id here, replace it by email/firstaccess combination): * 2A - Normal check: If match by username and mnethost and (email or non-zero firstaccess) => ok, return target user @@ -1187,7 +1189,16 @@ abstract class restore_dbops { return $rec; // Matching user found, return it } - // 1B - Handle users deleted in DB and "alive" in backup file + // 1B - If restoring an 'anonymous' user (created via the 'Anonymize user information' option) try to find a + // match by username only => ok, return target user MDL-31484 + // This avoids username / id mis-match problems when restoring subsequent anonymized backups. + if (backup_anonymizer_helper::is_anonymous_user($user)) { + if ($rec = $DB->get_record('user', array('username' => $user->username))) { + return $rec; // Matching anonymous user found - return it + } + } + + // 1C - Handle users deleted in DB and "alive" in backup file // Note: for DB deleted users email is stored in username field, hence we // are looking there for emails. See delete_user() // Note: for DB deleted users md5(username) is stored *sometimes* in the email field, @@ -1210,7 +1221,7 @@ abstract class restore_dbops { return $rec; // Matching user, deleted in DB found, return it } - // 1C - Handle users deleted in backup file and "alive" in DB + // 1D - Handle users deleted in backup file and "alive" in DB // If match by id and mnethost and user is deleted in backup file // and match by email = email_without_time(backup_email) => ok, return target user if ($user->deleted) { @@ -1228,7 +1239,7 @@ abstract class restore_dbops { } } - // 1D - If match by username and mnethost and doesn't match by id => conflict, return false + // 1E - If match by username and mnethost and doesn't match by id => conflict, return false if ($rec = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$user->mnethostid))) { if ($user->id != $rec->id) { return false; // Conflict, username already exists and belongs to another id diff --git a/backup/util/helper/backup_anonymizer_helper.class.php b/backup/util/helper/backup_anonymizer_helper.class.php index be56d2c2539..04a9d2da074 100644 --- a/backup/util/helper/backup_anonymizer_helper.class.php +++ b/backup/util/helper/backup_anonymizer_helper.class.php @@ -46,6 +46,24 @@ */ class backup_anonymizer_helper { + /** + * Determine if the given user is an 'anonymous' user, based on their username, firstname, lastname + * and email address. + * @param stdClass $user the user record to test + * @return bool true if this is an 'anonymous' user + */ + public static function is_anonymous_user($user) { + if (preg_match('/^anon\d*$/', $user->username)) { + $match = preg_match('/^anonfirstname\d*$/', $user->firstname); + $match = $match && preg_match('/^anonlastname\d*$/', $user->lastname); + $match = $match && preg_match('/^anon\d*@doesntexist\.com$/', $user->email); + if ($match) { + return true; + } + } + return false; + } + public static function process_user_auth($value) { return 'manual'; // Set them to manual always } diff --git a/backup/util/includes/restore_includes.php b/backup/util/includes/restore_includes.php index 8cbe6817e98..ae01911167c 100644 --- a/backup/util/includes/restore_includes.php +++ b/backup/util/includes/restore_includes.php @@ -34,6 +34,7 @@ require_once($CFG->dirroot . '/backup/util/interfaces/executable.class.php'); require_once($CFG->dirroot . '/backup/util/interfaces/processable.class.php'); require_once($CFG->dirroot . '/backup/backup.class.php'); require_once($CFG->dirroot . '/backup/util/structure/restore_path_element.class.php'); +require_once($CFG->dirroot . '/backup/util/helper/backup_anonymizer_helper.class.php'); require_once($CFG->dirroot . '/backup/util/helper/backup_file_manager.class.php'); require_once($CFG->dirroot . '/backup/util/helper/restore_prechecks_helper.class.php'); require_once($CFG->dirroot . '/backup/util/helper/restore_moodlexml_parser_processor.class.php'); -- 2.43.0