MDL-72950 restore: Avoid qcat conflicts with matching contexts

Though it's really rare for this to happen (it only was discovered
when running unit tests with Oracle), it's possible to get
problems restoring courses when context ids in the backup file
do match existing contexts in the restore target site in certain
ways (see the issue for more information).

This change just ensures that every call to the method (that
happens 4 times, for sys, coursecat, course and module levels):

prechek_precheck_qbanks_by_level()

Is processed always for that level. Before the patch it was
possible (hardly but possible) to return question categories
belonging to another level when some qcats contexts were matching
between the backup file and the target site.
This commit is contained in:
Eloy Lafuente (stronk7) 2021-10-31 16:17:35 +01:00
parent d135a1200a
commit c3a89cc550

View File

@ -619,7 +619,8 @@ abstract class restore_dbops {
// Top-level category counter.
$topcats = 0;
// get categories in context (bank)
$categories = self::restore_get_question_categories($restoreid, $contextid);
$categories = self::restore_get_question_categories($restoreid, $contextid, $contextlevel);
// cache permissions if $targetcontext is found
if ($targetcontext = self::restore_find_best_target_context($categories, $courseid, $contextlevel)) {
$canmanagecategory = has_capability('moodle/question:managecategory', $targetcontext, $userid);
@ -765,8 +766,13 @@ abstract class restore_dbops {
/**
* Return one array of question_category records for
* a given restore operation and one restore context (question bank)
*
* @param string $restoreid Unique identifier of the restore operation being performed.
* @param int $contextid Context id we want question categories to be returned.
* @param int $contextlevel Context level we want to restrict the returned categories.
* @return array Question categories for the given context id and level.
*/
public static function restore_get_question_categories($restoreid, $contextid) {
public static function restore_get_question_categories($restoreid, $contextid, $contextlevel) {
global $DB;
$results = array();
@ -776,7 +782,14 @@ abstract class restore_dbops {
AND itemname = 'question_category'
AND parentitemid = ?", array($restoreid, $contextid));
foreach ($qcats as $qcat) {
$results[$qcat->itemid] = backup_controller_dbops::decode_backup_temp_info($qcat->info);
$result = backup_controller_dbops::decode_backup_temp_info($qcat->info);
// Filter out found categories that belong to another context level.
// (this can happen when a higher level category becomes remapped to
// a context id that, by coincidence, matches a context id of another
// category at lower level). See MDL-72950 for more info.
if ($result->contextlevel == $contextlevel) {
$results[$qcat->itemid] = $result;
}
}
$qcats->close();