Línea 115... |
Línea 115... |
115 |
* @param string $restoreid Restore id
|
115 |
* @param string $restoreid Restore id
|
116 |
* @param string $inforeffile File path
|
116 |
* @param string $inforeffile File path
|
117 |
* @param \core\progress\base $progress Progress tracker
|
117 |
* @param \core\progress\base $progress Progress tracker
|
118 |
*/
|
118 |
*/
|
119 |
public static function load_inforef_to_tempids($restoreid, $inforeffile,
|
119 |
public static function load_inforef_to_tempids($restoreid, $inforeffile,
|
120 |
\core\progress\base $progress = null) {
|
120 |
?\core\progress\base $progress = null) {
|
Línea 121... |
Línea 121... |
121 |
|
121 |
|
122 |
if (!file_exists($inforeffile)) { // Shouldn't happen ever, but...
|
122 |
if (!file_exists($inforeffile)) { // Shouldn't happen ever, but...
|
123 |
throw new backup_helper_exception('missing_inforef_xml_file', $inforeffile);
|
123 |
throw new backup_helper_exception('missing_inforef_xml_file', $inforeffile);
|
Línea 422... |
Línea 422... |
422 |
* @param string $restoreid Restore id
|
422 |
* @param string $restoreid Restore id
|
423 |
* @param string $usersfile File path
|
423 |
* @param string $usersfile File path
|
424 |
* @param \core\progress\base $progress Progress tracker
|
424 |
* @param \core\progress\base $progress Progress tracker
|
425 |
*/
|
425 |
*/
|
426 |
public static function load_users_to_tempids($restoreid, $usersfile,
|
426 |
public static function load_users_to_tempids($restoreid, $usersfile,
|
427 |
\core\progress\base $progress = null) {
|
427 |
?\core\progress\base $progress = null) {
|
Línea 428... |
Línea 428... |
428 |
|
428 |
|
429 |
if (!file_exists($usersfile)) { // Shouldn't happen ever, but...
|
429 |
if (!file_exists($usersfile)) { // Shouldn't happen ever, but...
|
430 |
throw new backup_helper_exception('missing_users_xml_file', $usersfile);
|
430 |
throw new backup_helper_exception('missing_users_xml_file', $usersfile);
|
Línea 536... |
Línea 536... |
536 |
* This function will process all the question banks present in restore
|
536 |
* This function will process all the question banks present in restore
|
537 |
* at some contextlevel (from CONTEXT_SYSTEM to CONTEXT_MODULE), finding
|
537 |
* at some contextlevel (from CONTEXT_SYSTEM to CONTEXT_MODULE), finding
|
538 |
* the target contexts where each bank will be restored and returning
|
538 |
* the target contexts where each bank will be restored and returning
|
539 |
* warnings/errors as needed.
|
539 |
* warnings/errors as needed.
|
540 |
*
|
540 |
*
|
- |
|
541 |
* Question categories at CONTEXT_SYSTEM, CONTEXT_COURSE, and CONTEXT_COURSECAT
|
541 |
* Some contextlevels (system, coursecat), will delegate process to
|
542 |
* are now deprecated, but we still have to account for them in backup files
|
542 |
* course level if any problem is found (lack of permissions, non-matching
|
543 |
* made with pre-deprecated code. As such, any categories in backup files that used
|
543 |
* target context...). Other contextlevels (course, module) will
|
544 |
* to target these contexts will now be attached to a 'fallback' qbank
|
544 |
* cause return error if some problem is found.
|
545 |
* instance on the course being restored.
|
545 |
*
|
546 |
*
|
546 |
* At the end, if no errors were found, all the categories in backup_temp_ids
|
547 |
* At the end, if no errors were found, all the categories in backup_temp_ids
|
547 |
* will be pointing (parentitemid) to the target context where they must be
|
548 |
* will be pointing (parentitemid) to the target context where they must be
|
548 |
* created later in the restore process.
|
549 |
* created later in the restore process.
|
549 |
*
|
550 |
*
|
Línea 565... |
Línea 566... |
565 |
* @param bool $samesite True if restore is to same site
|
566 |
* @param bool $samesite True if restore is to same site
|
566 |
* @param int $contextlevel (CONTEXT_SYSTEM, etc.)
|
567 |
* @param int $contextlevel (CONTEXT_SYSTEM, etc.)
|
567 |
* @return array A separate list of all error and warnings detected
|
568 |
* @return array A separate list of all error and warnings detected
|
568 |
*/
|
569 |
*/
|
569 |
public static function prechek_precheck_qbanks_by_level($restoreid, $courseid, $userid, $samesite, $contextlevel) {
|
570 |
public static function prechek_precheck_qbanks_by_level($restoreid, $courseid, $userid, $samesite, $contextlevel) {
|
570 |
global $DB;
|
571 |
global $DB, $CFG;
|
Línea 571... |
Línea 572... |
571 |
|
572 |
|
572 |
// To return any errors and warnings found
|
573 |
// To return any errors and warnings found
|
573 |
$errors = array();
|
574 |
$errors = [];
|
574 |
$warnings = array();
|
- |
|
575 |
|
- |
|
576 |
// Specify which fallbacks must be performed
|
- |
|
577 |
$fallbacks = array(
|
- |
|
578 |
CONTEXT_SYSTEM => CONTEXT_COURSE,
|
- |
|
Línea 579... |
Línea 575... |
579 |
CONTEXT_COURSECAT => CONTEXT_COURSE);
|
575 |
$warnings = [];
|
580 |
|
576 |
|
581 |
/** @var restore_controller $rc */
|
577 |
/** @var restore_controller $rc */
|
582 |
$rc = restore_controller_dbops::load_controller($restoreid);
|
578 |
$rc = restore_controller_dbops::load_controller($restoreid);
|
583 |
$plan = $rc->get_plan();
|
579 |
$plan = $rc->get_plan();
|
Línea -... |
Línea 580... |
- |
|
580 |
$after35 = $plan->backup_release_compare('3.5', '>=') && $plan->backup_version_compare(20180205, '>');
|
584 |
$after35 = $plan->backup_release_compare('3.5', '>=') && $plan->backup_version_compare(20180205, '>');
|
581 |
$rc->destroy(); // Always need to destroy.
|
585 |
$rc->destroy(); // Always need to destroy.
|
582 |
|
586 |
|
583 |
/*
|
587 |
// For any contextlevel, follow this process logic:
|
584 |
For any contextlevel, follow this process logic:
|
588 |
//
|
585 |
|
589 |
// 0) Iterate over each context (qbank)
|
586 |
0) Iterate over each context (qbank)
|
590 |
// 1) Iterate over each qcat in the context, matching by stamp for the found target context
|
- |
|
591 |
// 2a) No match, check if user can create qcat and q
|
587 |
1) Iterate over each qcat in the context, matching by stamp for the found target context
|
592 |
// 3a) User can, mark the qcat and all dependent qs to be created in that target context
|
- |
|
593 |
// 3b) User cannot, check if we are in some contextlevel with fallback
|
588 |
2a) No match, check if user can create qcat and q
|
594 |
// 4a) There is fallback, move ALL the qcats to fallback, warn. End qcat loop
|
589 |
3a) User can, mark the qcat and all dependent qs to be created in that target context
|
595 |
// 4b) No fallback, error. End qcat loop.
|
590 |
3b) User cannot. Move ALL the qcats to a default qbank instance, warn. End qcat loop
|
596 |
// 2b) Match, mark qcat to be mapped and iterate over each q, matching by stamp and version
|
- |
|
597 |
// 5a) No match, check if user can add q
|
591 |
2b) Match, mark qcat to be mapped and iterate over each q, matching by stamp and version
|
598 |
// 6a) User can, mark the q to be created
|
- |
|
599 |
// 6b) User cannot, check if we are in some contextlevel with fallback
|
592 |
4a) No match, check if user can add q
|
600 |
// 7a) There is fallback, move ALL the qcats to fallback, warn. End qcat loop
|
593 |
5a) User can, mark the q to be created
|
601 |
// 7b) No fallback, error. End qcat loop
|
594 |
5b) User cannot. Move ALL the qcats to a default qbank instance, warn. End qcat loop
|
- |
|
595 |
4b) Random question, must always create new.
|
Línea 602... |
Línea 596... |
602 |
// 5b) Random question, must always create new.
|
596 |
4c) Match, mark q to be mapped
|
603 |
// 5c) Match, mark q to be mapped
|
597 |
6) Check if backup is from Moodle >= 3.5 and error if more than one top-level category in the context.
|
Línea 604... |
Línea 598... |
604 |
// 8) Check if backup is from Moodle >= 3.5 and error if more than one top-level category in the context.
|
598 |
*/
|
605 |
|
599 |
|
606 |
// Get all the contexts (question banks) in restore for the given contextlevel
|
600 |
// Get all the contexts (question banks) in restore for the given contextlevel
|
607 |
$contexts = self::restore_get_question_banks($restoreid, $contextlevel);
|
601 |
$contexts = self::restore_get_question_banks($restoreid, $contextlevel);
|
608 |
|
602 |
|
609 |
// 0) Iterate over each context (qbank)
|
603 |
// 0) Iterate over each context (qbank)
|
610 |
foreach ($contexts as $contextid => $contextlevel) {
|
604 |
foreach ($contexts as $contextid => $contextlevel) {
|
611 |
// Init some perms
|
605 |
// Init some perms
|
612 |
$canmanagecategory = false;
|
606 |
$canmanagecategory = false;
|
Línea 613... |
Línea 607... |
613 |
$canadd = false;
|
607 |
$canadd = false;
|
614 |
// Top-level category counter.
|
608 |
// Top-level category counter.
|
615 |
$topcats = 0;
|
609 |
$topcats = 0;
|
616 |
// get categories in context (bank)
|
610 |
// get categories in context (bank)
|
617 |
$categories = self::restore_get_question_categories($restoreid, $contextid, $contextlevel);
|
611 |
$categories = self::restore_get_question_categories($restoreid, $contextid, $contextlevel);
|
618 |
|
612 |
|
619 |
// cache permissions if $targetcontext is found
|
613 |
// cache permissions if $targetcontext is found
|
620 |
if ($targetcontext = self::restore_find_best_target_context($categories, $courseid, $contextlevel)) {
|
614 |
if ($targetcontext = self::restore_find_best_target_context($categories, $courseid, $contextlevel)) {
|
621 |
$canmanagecategory = has_capability('moodle/question:managecategory', $targetcontext, $userid);
|
615 |
$canmanagecategory = has_capability('moodle/question:managecategory', $targetcontext, $userid);
|
622 |
$canadd = has_capability('moodle/question:add', $targetcontext, $userid);
|
616 |
$canadd = has_capability('moodle/question:add', $targetcontext, $userid);
|
Línea 623... |
Línea 617... |
623 |
}
|
617 |
}
|
624 |
// 1) Iterate over each qcat in the context, matching by stamp for the found target context
|
618 |
// 1) Iterate over each qcat in the context, matching by stamp for the found target context
|
625 |
foreach ($categories as $category) {
|
619 |
foreach ($categories as $category) {
|
626 |
if ($category->parent == 0) {
|
620 |
if ($category->parent == 0) {
|
627 |
$topcats++;
|
621 |
$topcats++;
|
- |
|
622 |
}
|
628 |
}
|
623 |
|
629 |
|
624 |
$matchcat = false;
|
630 |
$matchcat = false;
|
625 |
if ($targetcontext) {
|
631 |
if ($targetcontext) {
|
626 |
$matchcat = $DB->get_record('question_categories', [
|
632 |
$matchcat = $DB->get_record('question_categories', array(
|
627 |
'contextid' => $targetcontext->id,
|
Línea 644... |
Línea 639... |
644 |
if ($contextlevel == CONTEXT_MODULE) {
|
639 |
if ($contextlevel == CONTEXT_MODULE) {
|
645 |
$parentitemid = null; // null means "not modify" a.k.a. leave original contextid
|
640 |
$parentitemid = null; // null means "not modify" a.k.a. leave original contextid
|
646 |
}
|
641 |
}
|
647 |
self::set_backup_ids_record($restoreid, 'question_category', $category->id, 0, $parentitemid);
|
642 |
self::set_backup_ids_record($restoreid, 'question_category', $category->id, 0, $parentitemid);
|
648 |
// Nothing else to mark, newitemid = 0 means create
|
643 |
// Nothing else to mark, newitemid = 0 means create
|
649 |
|
- |
|
650 |
// 3b) User cannot, check if we are in some contextlevel with fallback
|
- |
|
651 |
} else {
|
644 |
} else {
|
652 |
// 4a) There is fallback, move ALL the qcats to fallback, warn. End qcat loop
|
645 |
// 3b) User cannot. Move ALL the qcats to the fallback i.e. a default qbank instance, warn. End qcat loop.
|
- |
|
646 |
$course = get_course($courseid);
|
- |
|
647 |
$course->fullname = get_string('courserestore', 'question');
|
- |
|
648 |
$module =
|
- |
|
649 |
core_question\local\bank\question_bank_helper::get_default_open_instance_system_type($course, true);
|
653 |
if (array_key_exists($contextlevel, $fallbacks)) {
|
650 |
$fallbackcontext = $module->context;
|
654 |
foreach ($categories as $movedcat) {
|
651 |
foreach ($categories as $movedcat) {
|
655 |
$movedcat->contextlevel = $fallbacks[$contextlevel];
|
652 |
$movedcat->contextlevel = $contextlevel;
|
656 |
self::set_backup_ids_record($restoreid, 'question_category', $movedcat->id, 0, $contextid, $movedcat);
|
653 |
self::set_backup_ids_record($restoreid,
|
657 |
// Warn about the performed fallback
|
654 |
'question_category',
|
658 |
$warnings[] = get_string('qcategory2coursefallback', 'backup', $movedcat);
|
655 |
$movedcat->id,
|
659 |
}
|
656 |
0,
|
660 |
|
- |
|
661 |
// 4b) No fallback, error. End qcat loop.
|
657 |
$fallbackcontext->id,
|
- |
|
658 |
$movedcat
|
662 |
} else {
|
659 |
);
|
- |
|
660 |
// Warn about the performed fallback.
|
663 |
$errors[] = get_string('qcategorycannotberestored', 'backup', $category);
|
661 |
$warnings[] = get_string('qcategory2coursefallback', 'backup', $movedcat);
|
664 |
}
|
662 |
}
|
665 |
break; // out from qcat loop (both 4a and 4b), we have decided about ALL categories in context (bank)
|
663 |
break; // Out from qcat loop (both 3a and 3b), we have decided about ALL categories in context (bank).
|
666 |
}
|
664 |
}
|
Línea 667... |
Línea 665... |
667 |
|
665 |
|
668 |
// 2b) Match, mark qcat to be mapped and iterate over each q, matching by stamp and version
|
666 |
// 2b) Match, mark qcat to be mapped and iterate over each q, matching by stamp and version
|
669 |
} else {
|
667 |
} else {
|
670 |
self::set_backup_ids_record($restoreid, 'question_category', $category->id, $matchcat->id, $targetcontext->id);
|
668 |
self::set_backup_ids_record($restoreid, 'question_category', $category->id, $matchcat->id, $targetcontext->id);
|
- |
|
669 |
$questions = self::restore_get_questions($restoreid, $category->id);
|
Línea 671... |
Línea 670... |
671 |
$questions = self::restore_get_questions($restoreid, $category->id);
|
670 |
$transformer = self::get_backup_xml_transformer($courseid);
|
672 |
|
671 |
|
673 |
// Collect all the questions for this category into memory so we only talk to the DB once.
|
672 |
// Collect all the questions for this category into memory so we only talk to the DB once.
|
674 |
$questioncache = $DB->get_records_sql_menu('SELECT q.id,
|
673 |
$recordset = $DB->get_recordset_sql(
|
675 |
q.stamp
|
674 |
"SELECT q.*
|
676 |
FROM {question} q
|
675 |
FROM {question} q
|
677 |
JOIN {question_versions} qv
|
676 |
JOIN {question_versions} qv ON qv.questionid = q.id
|
- |
|
677 |
JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
|
- |
|
678 |
JOIN {question_categories} qc ON qc.id = qbe.questioncategoryid
|
- |
|
679 |
WHERE qc.id = ?",
|
- |
|
680 |
[$matchcat->id],
|
- |
|
681 |
);
|
- |
|
682 |
|
- |
|
683 |
// Compute a hash of question and answer fields to differentiate between identical stamp-version questions.
|
678 |
ON qv.questionid = q.id
|
684 |
$questioncache = [];
|
- |
|
685 |
foreach ($recordset as $question) {
|
- |
|
686 |
$question->export_process = true; // Include all question options required for export.
|
679 |
JOIN {question_bank_entries} qbe
|
687 |
get_question_options($question);
|
- |
|
688 |
unset($question->export_process);
|
- |
|
689 |
// Remove some additional properties from get_question_options() that isn't included in backups
|
680 |
ON qbe.id = qv.questionbankentryid
|
690 |
// before we produce the identity hash.
|
681 |
JOIN {question_categories} qc
|
691 |
unset($question->categoryobject);
|
- |
|
692 |
unset($question->questioncategoryid);
|
- |
|
693 |
$cachekey = restore_questions_parser_processor::generate_question_identity_hash($question, $transformer);
|
- |
|
694 |
$questioncache[$cachekey] = $question->id;
|
Línea 682... |
Línea 695... |
682 |
ON qc.id = qbe.questioncategoryid
|
695 |
}
|
683 |
WHERE qc.id = ?', array($matchcat->id));
|
696 |
$recordset->close();
|
684 |
|
697 |
|
685 |
foreach ($questions as $question) {
|
698 |
foreach ($questions as $question) {
|
686 |
if (isset($questioncache[$question->stamp." ".$question->version])) {
|
699 |
if (isset($questioncache[$question->questionhash])) {
|
687 |
$matchqid = $questioncache[$question->stamp." ".$question->version];
|
700 |
$matchqid = $questioncache[$question->questionhash];
|
688 |
} else {
|
701 |
} else {
|
689 |
$matchqid = false;
|
702 |
$matchqid = false;
|
690 |
}
|
703 |
}
|
691 |
// 5a) No match, check if user can add q
|
704 |
// 4a) No match, check if user can add q
|
692 |
if (!$matchqid) {
|
705 |
if (!$matchqid) {
|
693 |
// 6a) User can, mark the q to be created
|
- |
|
694 |
if ($canadd) {
|
- |
|
695 |
// Nothing to mark, newitemid means create
|
706 |
// 5a) User can, mark the q to be created
|
- |
|
707 |
if ($canadd) {
|
696 |
|
708 |
// Nothing to mark, newitemid means create
|
- |
|
709 |
} else {
|
- |
|
710 |
// 5b) User cannot.
|
- |
|
711 |
// Move ALL the qcats to the fallback i.e. a default qbank instance, warn. End qcat loop.
|
- |
|
712 |
$course = get_course($courseid);
|
- |
|
713 |
$course->fullname = get_string('courserestore', 'question');
|
- |
|
714 |
$module = core_question\local\bank\question_bank_helper::get_default_open_instance_system_type(
|
697 |
// 6b) User cannot, check if we are in some contextlevel with fallback
|
715 |
$course,
|
698 |
} else {
|
716 |
true
|
699 |
// 7a) There is fallback, move ALL the qcats to fallback, warn. End qcat loo
|
717 |
);
|
700 |
if (array_key_exists($contextlevel, $fallbacks)) {
|
718 |
$fallbackcontext = $module->context;
|
701 |
foreach ($categories as $movedcat) {
|
719 |
foreach ($categories as $movedcat) {
|
702 |
$movedcat->contextlevel = $fallbacks[$contextlevel];
|
720 |
$movedcat->contextlevel = $contextlevel;
|
703 |
self::set_backup_ids_record($restoreid, 'question_category', $movedcat->id, 0, $contextid, $movedcat);
|
721 |
self::set_backup_ids_record($restoreid,
|
704 |
// Warn about the performed fallback
|
- |
|
705 |
$warnings[] = get_string('question2coursefallback', 'backup', $movedcat);
|
722 |
'question_category',
|
- |
|
723 |
$movedcat->id,
|
706 |
}
|
724 |
0,
|
- |
|
725 |
$fallbackcontext->id,
|
707 |
|
726 |
$movedcat
|
708 |
// 7b) No fallback, error. End qcat loop
|
727 |
);
|
709 |
} else {
|
728 |
// Warn about the performed fallback.
|
- |
|
729 |
$warnings[] = get_string('question2coursefallback', 'backup', $movedcat);
|
710 |
$errors[] = get_string('questioncannotberestored', 'backup', $question);
|
730 |
}
|
Línea 711... |
Línea 731... |
711 |
}
|
731 |
// Out from qcat loop (both 5a and 5b), we have decided about ALL categories in context (bank).
|
712 |
break 2; // out from qcat loop (both 7a and 7b), we have decided about ALL categories in context (bank)
|
732 |
break 2;
|
713 |
}
|
733 |
}
|
Línea 714... |
Línea 734... |
714 |
|
734 |
|
715 |
// 5b) Random questions must always be newly created.
|
735 |
// 4b) Random questions must always be newly created.
|
716 |
} else if ($question->qtype == 'random') {
|
736 |
} else if ($question->qtype == 'random') {
|
717 |
// Nothing to mark, newitemid means create
|
737 |
// Nothing to mark, newitemid means create
|
718 |
|
738 |
|
719 |
// 5c) Match, mark q to be mapped.
|
739 |
// 4c) Match, mark q to be mapped.
|
720 |
} else {
|
740 |
} else {
|
Línea 721... |
Línea 741... |
721 |
self::set_backup_ids_record($restoreid, 'question', $question->id, $matchqid);
|
741 |
self::set_backup_ids_record($restoreid, 'question', $question->id, $matchqid);
|
722 |
}
|
742 |
}
|
723 |
}
|
743 |
}
|
724 |
}
|
744 |
}
|
Línea 725... |
Línea 745... |
725 |
}
|
745 |
}
|
Línea 726... |
Línea 746... |
726 |
|
746 |
|
727 |
// 8) Check if backup is made on Moodle >= 3.5 and there are more than one top-level category in the context.
|
747 |
// 6) Check if backup is made on Moodle >= 3.5 and there are more than one top-level category in the context.
|
Línea 728... |
Línea 748... |
728 |
if ($after35 && $topcats > 1) {
|
748 |
if ($after35 && $topcats > 1) {
|
729 |
$errors[] = get_string('restoremultipletopcats', 'question', $contextid);
|
749 |
$errors[] = get_string('restoremultipletopcats', 'question', $contextid);
|
730 |
}
|
750 |
}
|
Línea 797... |
Línea 817... |
797 |
|
817 |
|
798 |
return $results;
|
818 |
return $results;
|
Línea 799... |
Línea 819... |
799 |
}
|
819 |
}
|
800 |
|
820 |
|
- |
|
821 |
/**
|
801 |
/**
|
822 |
* Calculates the best existing context to restore one collection of qcats.
|
- |
|
823 |
* Uses the backup category stamp to match the target category stamp
|
- |
|
824 |
* and categories must all belong to the same context (question bank).
|
802 |
* Calculates the best context found to restore one collection of qcats,
|
825 |
*
|
- |
|
826 |
* @param array $categories categories to find target context for
|
- |
|
827 |
* @param int $courseid course to restore to
|
803 |
* al them belonging to the same context (question bank), returning the
|
828 |
* @param int $contextlevel contextlevel to search for the target context
|
804 |
* target context found (object) or false
|
829 |
* @return bool|\core\context target context or false if no target context found
|
805 |
*/
|
830 |
*/
|
Línea 806... |
Línea 831... |
806 |
public static function restore_find_best_target_context($categories, $courseid, $contextlevel) {
|
831 |
public static function restore_find_best_target_context($categories, $courseid, $contextlevel) {
|
Línea 807... |
Línea -... |
807 |
global $DB;
|
- |
|
808 |
|
- |
|
809 |
$targetcontext = false;
|
- |
|
810 |
|
- |
|
811 |
// Depending of $contextlevel, we perform different actions
|
- |
|
812 |
switch ($contextlevel) {
|
- |
|
813 |
// For system is easy, the best context is the system context
|
- |
|
814 |
case CONTEXT_SYSTEM:
|
- |
|
815 |
$targetcontext = context_system::instance();
|
- |
|
816 |
break;
|
832 |
global $DB;
|
817 |
|
- |
|
818 |
// For coursecat, we are going to look for stamps in all the
|
- |
|
819 |
// course categories between CONTEXT_SYSTEM and CONTEXT_COURSE
|
- |
|
820 |
// (i.e. in all the course categories in the path)
|
833 |
|
821 |
//
|
834 |
$targetcontext = false;
|
822 |
// And only will return one "best" target context if all the
|
835 |
|
823 |
// matches belong to ONE and ONLY ONE context. If multiple
|
836 |
// If context module we need to find any existing module instances with categories matching the category stamps
|
824 |
// matches are found, that means that there is some annoying
|
- |
|
825 |
// qbank "fragmentation" in the categories, so we'll fallback
|
837 |
// from the backup. If multiple matches are found, that means that there is some annoying
|
826 |
// to create the qbank at course level
|
838 |
// qbank "fragmentation" in the categories, so we'll fall back
|
827 |
case CONTEXT_COURSECAT:
|
839 |
// to creating a qbank instance at course level and putting the categories there.
|
828 |
// Build the array of stamps we are going to match
|
840 |
if ($contextlevel == CONTEXT_MODULE) {
|
829 |
$stamps = array();
|
841 |
$stamps = [];
|
- |
|
842 |
foreach ($categories as $category) {
|
830 |
foreach ($categories as $category) {
|
843 |
$stamps[] = $category->stamp;
|
831 |
$stamps[] = $category->stamp;
|
844 |
}
|
832 |
}
|
- |
|
833 |
$contexts = array();
|
- |
|
834 |
// Build the array of contexts we are going to look
|
845 |
$modinfo = get_fast_modinfo($courseid);
|
835 |
$systemctx = context_system::instance();
|
846 |
|
836 |
$coursectx = context_course::instance($courseid);
|
847 |
// Get contextids of modules from the course that support publishing questions.
|
837 |
$parentctxs = $coursectx->get_parent_context_ids();
|
- |
|
838 |
foreach ($parentctxs as $parentctx) {
|
848 |
$supportedcontextids = [];
|
839 |
// Exclude system context
|
- |
|
840 |
if ($parentctx == $systemctx->id) {
|
849 |
foreach ($modinfo->get_cms() as $cm) {
|
- |
|
850 |
if (plugin_supports('mod', $cm->modname, FEATURE_PUBLISHES_QUESTIONS, false)) {
|
841 |
continue;
|
851 |
$supportedcontextids[] = $cm->context->id;
|
842 |
}
|
- |
|
843 |
$contexts[] = $parentctx;
|
852 |
}
|
844 |
}
|
853 |
}
|
845 |
if (!empty($stamps) && !empty($contexts)) {
|
854 |
|
846 |
// Prepare the query
|
855 |
if (!empty($stamps) && !empty($supportedcontextids)) {
|
847 |
list($stamp_sql, $stamp_params) = $DB->get_in_or_equal($stamps);
|
856 |
[$stampsql, $stampparams] = $DB->get_in_or_equal($stamps);
|
848 |
list($context_sql, $context_params) = $DB->get_in_or_equal($contexts);
|
857 |
[$contextsql, $contextparams] = $DB->get_in_or_equal($supportedcontextids);
|
849 |
$sql = "SELECT DISTINCT contextid
|
858 |
$sql = "SELECT DISTINCT contextid
|
850 |
FROM {question_categories}
|
859 |
FROM {question_categories}
|
851 |
WHERE stamp $stamp_sql
|
860 |
WHERE stamp {$stampsql}
|
852 |
AND contextid $context_sql";
|
861 |
AND contextid {$contextsql}";
|
853 |
$params = array_merge($stamp_params, $context_params);
|
862 |
$params = array_merge($stampparams, $contextparams);
|
854 |
$matchingcontexts = $DB->get_records_sql($sql, $params);
|
863 |
$matchingcontexts = $DB->get_records_sql($sql, $params);
|
855 |
// Only if ONE and ONLY ONE context is found, use it as valid target
|
864 |
// Only if ONE and ONLY ONE context is found, use it as valid target.
|
856 |
if (count($matchingcontexts) == 1) {
|
- |
|
857 |
$targetcontext = context::instance_by_id(reset($matchingcontexts)->contextid);
|
- |
|
858 |
}
|
865 |
if (count($matchingcontexts) === 1) {
|
859 |
}
|
- |
|
860 |
break;
|
- |
|
861 |
|
- |
|
862 |
// For course is easy, the best context is the course context
|
- |
|
863 |
case CONTEXT_COURSE:
|
- |
|
864 |
$targetcontext = context_course::instance($courseid);
|
- |
|
865 |
break;
|
- |
|
866 |
|
- |
|
867 |
// For module is easy, there is not best context, as far as the
|
- |
|
868 |
// activity hasn't been created yet. So we return context course
|
- |
|
869 |
// for them, so permission checks and friends will work. Note this
|
866 |
$targetcontext = context::instance_by_id(reset($matchingcontexts)->contextid);
|
870 |
// case is handled by {@link prechek_precheck_qbanks_by_level}
|
- |
|
871 |
// in an special way
|
867 |
}
|
- |
|
868 |
}
|
872 |
case CONTEXT_MODULE:
|
869 |
// We don't have a target so set as course context until the module is created and then assign to the module context.
|
873 |
$targetcontext = context_course::instance($courseid);
|
870 |
$targetcontext = $targetcontext ?: context_course::instance($courseid);
|
Línea 874... |
Línea 871... |
874 |
break;
|
871 |
}
|
875 |
}
|
872 |
|
Línea 918... |
Línea 915... |
918 |
* @return array of result object
|
915 |
* @return array of result object
|
919 |
*/
|
916 |
*/
|
920 |
public static function send_files_to_pool($basepath, $restoreid, $component, $filearea,
|
917 |
public static function send_files_to_pool($basepath, $restoreid, $component, $filearea,
|
921 |
$oldcontextid, $dfltuserid, $itemname = null, $olditemid = null,
|
918 |
$oldcontextid, $dfltuserid, $itemname = null, $olditemid = null,
|
922 |
$forcenewcontextid = null, $skipparentitemidctxmatch = false,
|
919 |
$forcenewcontextid = null, $skipparentitemidctxmatch = false,
|
923 |
\core\progress\base $progress = null) {
|
920 |
?\core\progress\base $progress = null) {
|
924 |
global $DB, $CFG;
|
921 |
global $DB, $CFG;
|
Línea 925... |
Línea 922... |
925 |
|
922 |
|
926 |
$backupinfo = backup_general_helper::get_backup_information(basename($basepath));
|
923 |
$backupinfo = backup_general_helper::get_backup_information(basename($basepath));
|
Línea 1736... |
Línea 1733... |
1736 |
* @param int $userid User id
|
1733 |
* @param int $userid User id
|
1737 |
* @param bool $samesite True if restore is to same site
|
1734 |
* @param bool $samesite True if restore is to same site
|
1738 |
* @param \core\progress\base $progress Optional progress tracker
|
1735 |
* @param \core\progress\base $progress Optional progress tracker
|
1739 |
*/
|
1736 |
*/
|
1740 |
public static function process_included_users($restoreid, $courseid, $userid, $samesite,
|
1737 |
public static function process_included_users($restoreid, $courseid, $userid, $samesite,
|
1741 |
\core\progress\base $progress = null) {
|
1738 |
?\core\progress\base $progress = null) {
|
1742 |
global $DB;
|
1739 |
global $DB;
|
Línea 1743... |
Línea 1740... |
1743 |
|
1740 |
|
1744 |
// Just let precheck_included_users() to do all the hard work
|
1741 |
// Just let precheck_included_users() to do all the hard work
|
Línea 1825... |
Línea 1822... |
1825 |
$suffixfull = '';
|
1822 |
$suffixfull = '';
|
1826 |
$suffixshort = '';
|
1823 |
$suffixshort = '';
|
1827 |
}
|
1824 |
}
|
Línea 1828... |
Línea 1825... |
1828 |
|
1825 |
|
- |
|
1826 |
// Ensure we don't overflow maximum length of name fields, in multi-byte safe manner.
|
1829 |
// Ensure we don't overflow maximum length of name fields, in multi-byte safe manner.
|
1827 |
$currentfullname = core_text::substr($fullname, 0,
|
- |
|
1828 |
\core_course\constants::FULLNAME_MAXIMUM_LENGTH - strlen($suffixfull)) . $suffixfull;
|
1830 |
$currentfullname = core_text::substr($fullname, 0, 254 - strlen($suffixfull)) . $suffixfull;
|
1829 |
$currentshortname = core_text::substr($shortname, 0,
|
Línea 1831... |
Línea 1830... |
1831 |
$currentshortname = core_text::substr($shortname, 0, 100 - strlen($suffixshort)) . $suffixshort;
|
1830 |
\core_course\constants::SHORTNAME_MAXIMUM_LENGTH - strlen($suffixshort)) . $suffixshort;
|
1832 |
|
1831 |
|
1833 |
$coursefull = $DB->get_record_select('course', 'fullname = ? AND id != ?',
|
1832 |
$coursefull = $DB->get_record_select('course', 'fullname = ? AND id != ?',
|
1834 |
array($currentfullname, $courseid), '*', IGNORE_MULTIPLE);
|
1833 |
array($currentfullname, $courseid), '*', IGNORE_MULTIPLE);
|
Línea 1903... |
Línea 1902... |
1903 |
* Deletes all of the content associated with the given course (courseid)
|
1902 |
* Deletes all of the content associated with the given course (courseid)
|
1904 |
* @param int $courseid
|
1903 |
* @param int $courseid
|
1905 |
* @param array $options
|
1904 |
* @param array $options
|
1906 |
* @return bool True for success
|
1905 |
* @return bool True for success
|
1907 |
*/
|
1906 |
*/
|
1908 |
public static function delete_course_content($courseid, array $options = null) {
|
1907 |
public static function delete_course_content($courseid, ?array $options = null) {
|
1909 |
return remove_course_contents($courseid, false, $options);
|
1908 |
return remove_course_contents($courseid, false, $options);
|
1910 |
}
|
1909 |
}
|
Línea 1911... |
Línea 1910... |
1911 |
|
1910 |
|
1912 |
/**
|
1911 |
/**
|
Línea 1917... |
Línea 1916... |
1917 |
* @return bool
|
1916 |
* @return bool
|
1918 |
*/
|
1917 |
*/
|
1919 |
private static function password_should_be_discarded(#[\SensitiveParameter] string $password): bool {
|
1918 |
private static function password_should_be_discarded(#[\SensitiveParameter] string $password): bool {
|
1920 |
return (bool) preg_match('/^[0-9a-f]{32}$/', $password);
|
1919 |
return (bool) preg_match('/^[0-9a-f]{32}$/', $password);
|
1921 |
}
|
1920 |
}
|
- |
|
1921 |
|
- |
|
1922 |
/**
|
- |
|
1923 |
* Load required classes and return a backup XML transformer for the specified course.
|
- |
|
1924 |
*
|
- |
|
1925 |
* These classes may not have been loaded if we're only doing a restore in the current process,
|
- |
|
1926 |
* so make sure we have them here.
|
- |
|
1927 |
*
|
- |
|
1928 |
* @param int $courseid
|
- |
|
1929 |
* @return backup_xml_transformer
|
- |
|
1930 |
*/
|
- |
|
1931 |
protected static function get_backup_xml_transformer(int $courseid): backup_xml_transformer {
|
- |
|
1932 |
global $CFG;
|
- |
|
1933 |
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
- |
|
1934 |
require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
|
- |
|
1935 |
return new backup_xml_transformer($courseid);
|
- |
|
1936 |
}
|
1922 |
}
|
1937 |
}
|
Línea 1923... |
Línea 1938... |
1923 |
|
1938 |
|
1924 |
/*
|
1939 |
/*
|
1925 |
* Exception class used by all the @dbops stuff
|
1940 |
* Exception class used by all the @dbops stuff
|