MDL-77086 badges: Improve debugging
[moodle.git] / lib / db / upgrade.php
bloba00bb82a04dc0c5c2b9437863b2f9e76513cbaf6
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * This file keeps track of upgrades to Moodle.
20 * Sometimes, changes between versions involve
21 * alterations to database structures and other
22 * major things that may break installations.
24 * The upgrade function in this file will attempt
25 * to perform all the necessary actions to upgrade
26 * your older installation to the current version.
28 * If there's something it cannot do itself, it
29 * will tell you what you need to do.
31 * The commands in here will all be database-neutral,
32 * using the methods of database_manager class
34 * Please do not forget to use upgrade_set_timeout()
35 * before any action that may take longer time to finish.
37 * @package core_install
38 * @category upgrade
39 * @copyright 2006 onwards Martin Dougiamas http://dougiamas.com
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43 defined('MOODLE_INTERNAL') || die();
45 /**
46 * Main upgrade tasks to be executed on Moodle version bump
48 * This function is automatically executed after one bump in the Moodle core
49 * version is detected. It's in charge of performing the required tasks
50 * to raise core from the previous version to the next one.
52 * It's a collection of ordered blocks of code, named "upgrade steps",
53 * each one performing one isolated (from the rest of steps) task. Usually
54 * tasks involve creating new DB objects or performing manipulation of the
55 * information for cleanup/fixup purposes.
57 * Each upgrade step has a fixed structure, that can be summarised as follows:
59 * if ($oldversion < XXXXXXXXXX.XX) {
60 * // Explanation of the update step, linking to issue in the Tracker if necessary
61 * upgrade_set_timeout(XX); // Optional for big tasks
62 * // Code to execute goes here, usually the XMLDB Editor will
63 * // help you here. See {@link http://docs.moodle.org/dev/XMLDB_editor}.
64 * upgrade_main_savepoint(true, XXXXXXXXXX.XX);
65 * }
67 * All plugins within Moodle (modules, blocks, reports...) support the existence of
68 * their own upgrade.php file, using the "Frankenstyle" component name as
69 * defined at {@link http://docs.moodle.org/dev/Frankenstyle}, for example:
70 * - {@link xmldb_page_upgrade($oldversion)}. (modules don't require the plugintype ("mod_") to be used.
71 * - {@link xmldb_auth_manual_upgrade($oldversion)}.
72 * - {@link xmldb_workshopform_accumulative_upgrade($oldversion)}.
73 * - ....
75 * In order to keep the contents of this file reduced, it's allowed to create some helper
76 * functions to be used here in the {@link upgradelib.php} file at the same directory. Note
77 * that such a file must be manually included from upgrade.php, and there are some restrictions
78 * about what can be used within it.
80 * For more information, take a look to the documentation available:
81 * - Data definition API: {@link http://docs.moodle.org/dev/Data_definition_API}
82 * - Upgrade API: {@link http://docs.moodle.org/dev/Upgrade_API}
84 * @param int $oldversion
85 * @return bool always true
87 function xmldb_main_upgrade($oldversion) {
88 global $CFG, $DB;
90 require_once($CFG->libdir.'/db/upgradelib.php'); // Core Upgrade-related functions.
92 $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes.
94 // Always keep this upgrade step with version being the minimum
95 // allowed version to upgrade from (v3.11.8 right now).
96 if ($oldversion < 2021051708) {
97 // Just in case somebody hacks upgrade scripts or env, we really can not continue.
98 echo("You need to upgrade to 3.11.8 or higher first!\n");
99 exit(1);
100 // Note this savepoint is 100% unreachable, but needed to pass the upgrade checks.
101 upgrade_main_savepoint(true, 2021051708);
104 if ($oldversion < 2021052500.01) {
105 // Delete all user evidence files from users that have been deleted.
106 $sql = "SELECT DISTINCT f.*
107 FROM {files} f
108 LEFT JOIN {context} c ON f.contextid = c.id
109 WHERE f.component = :component
110 AND f.filearea = :filearea
111 AND c.id IS NULL";
112 $stalefiles = $DB->get_records_sql($sql, ['component' => 'core_competency', 'filearea' => 'userevidence']);
114 $fs = get_file_storage();
115 foreach ($stalefiles as $stalefile) {
116 $fs->get_file_instance($stalefile)->delete();
119 upgrade_main_savepoint(true, 2021052500.01);
122 if ($oldversion < 2021052500.02) {
124 // Define field timecreated to be added to task_adhoc.
125 $table = new xmldb_table('task_adhoc');
126 $field = new xmldb_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'blocking');
128 // Conditionally launch add field timecreated.
129 if (!$dbman->field_exists($table, $field)) {
130 $dbman->add_field($table, $field);
133 // Main savepoint reached.
134 upgrade_main_savepoint(true, 2021052500.02);
137 if ($oldversion < 2021052500.04) {
138 // Define field metadatasettings to be added to h5p_libraries.
139 $table = new xmldb_table('h5p_libraries');
140 $field = new xmldb_field('metadatasettings', XMLDB_TYPE_TEXT, null, null, null, null, null, 'coreminor');
142 // Conditionally launch add field metadatasettings.
143 if (!$dbman->field_exists($table, $field)) {
144 $dbman->add_field($table, $field);
147 // Get installed library files that have no metadata settings value.
148 $params = [
149 'component' => 'core_h5p',
150 'filearea' => 'libraries',
151 'filename' => 'library.json',
153 $sql = "SELECT l.id, f.id as fileid
154 FROM {files} f
155 LEFT JOIN {h5p_libraries} l ON f.itemid = l.id
156 WHERE f.component = :component
157 AND f.filearea = :filearea
158 AND f.filename = :filename";
159 $libraries = $DB->get_records_sql($sql, $params);
161 // Update metadatasettings field when the attribute is present in the library.json file.
162 $fs = get_file_storage();
163 foreach ($libraries as $library) {
164 $jsonfile = $fs->get_file_by_id($library->fileid);
165 $jsoncontent = json_decode($jsonfile->get_content());
166 if (isset($jsoncontent->metadataSettings)) {
167 unset($library->fileid);
168 $library->metadatasettings = json_encode($jsoncontent->metadataSettings);
169 $DB->update_record('h5p_libraries', $library);
173 // Main savepoint reached.
174 upgrade_main_savepoint(true, 2021052500.04);
177 if ($oldversion < 2021052500.05) {
178 // Define fields to be added to task_scheduled.
179 $table = new xmldb_table('task_scheduled');
180 $field = new xmldb_field('timestarted', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'disabled');
181 if (!$dbman->field_exists($table, $field)) {
182 $dbman->add_field($table, $field);
184 $field = new xmldb_field('hostname', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'timestarted');
185 if (!$dbman->field_exists($table, $field)) {
186 $dbman->add_field($table, $field);
188 $field = new xmldb_field('pid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'hostname');
189 if (!$dbman->field_exists($table, $field)) {
190 $dbman->add_field($table, $field);
193 // Define fields to be added to task_adhoc.
194 $table = new xmldb_table('task_adhoc');
195 $field = new xmldb_field('timestarted', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'blocking');
196 if (!$dbman->field_exists($table, $field)) {
197 $dbman->add_field($table, $field);
199 $field = new xmldb_field('hostname', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'timestarted');
200 if (!$dbman->field_exists($table, $field)) {
201 $dbman->add_field($table, $field);
203 $field = new xmldb_field('pid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'hostname');
204 if (!$dbman->field_exists($table, $field)) {
205 $dbman->add_field($table, $field);
208 // Define fields to be added to task_log.
209 $table = new xmldb_table('task_log');
210 $field = new xmldb_field('hostname', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'output');
211 if (!$dbman->field_exists($table, $field)) {
212 $dbman->add_field($table, $field);
214 $field = new xmldb_field('pid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'hostname');
215 if (!$dbman->field_exists($table, $field)) {
216 $dbman->add_field($table, $field);
219 // Main savepoint reached.
220 upgrade_main_savepoint(true, 2021052500.05);
223 if ($oldversion < 2021052500.06) {
224 // Define table to store virus infected details.
225 $table = new xmldb_table('infected_files');
227 // Adding fields to table infected_files.
228 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
229 $table->add_field('filename', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
230 $table->add_field('quarantinedfile', XMLDB_TYPE_TEXT, null, null, null, null, null);
231 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
232 $table->add_field('reason', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
233 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
235 // Adding keys to table infected_files.
236 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
237 $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
239 // Conditionally launch create table for infected_files.
240 if (!$dbman->table_exists($table)) {
241 $dbman->create_table($table);
243 upgrade_main_savepoint(true, 2021052500.06);
246 if ($oldversion < 2021052500.13) {
247 // Remove all the files with component='core_h5p' and filearea='editor' because they won't be used anymore.
248 $fs = get_file_storage();
249 $syscontext = context_system::instance();
250 $fs->delete_area_files($syscontext->id, 'core_h5p', 'editor');
252 // Main savepoint reached.
253 upgrade_main_savepoint(true, 2021052500.13);
256 if ($oldversion < 2021052500.15) {
257 // Copy From id captures the id of the source course when a new course originates from a restore
258 // of another course on the same site.
259 $table = new xmldb_table('course');
260 $field = new xmldb_field('originalcourseid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
262 if (!$dbman->field_exists($table, $field)) {
263 $dbman->add_field($table, $field);
266 // Main savepoint reached.
267 upgrade_main_savepoint(true, 2021052500.15);
270 if ($oldversion < 2021052500.19) {
271 // Define table oauth2_refresh_token to be created.
272 $table = new xmldb_table('oauth2_refresh_token');
274 // Adding fields to table oauth2_refresh_token.
275 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
276 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
277 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
278 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
279 $table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
280 $table->add_field('token', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
281 $table->add_field('scopehash', XMLDB_TYPE_CHAR, 40, null, XMLDB_NOTNULL, null, null);
283 // Adding keys to table oauth2_refresh_token.
284 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
285 $table->add_key('issueridkey', XMLDB_KEY_FOREIGN, ['issuerid'], 'oauth2_issuer', ['id']);
286 $table->add_key('useridkey', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
288 // Adding indexes to table oauth2_refresh_token.
289 $table->add_index('userid-issuerid-scopehash', XMLDB_INDEX_UNIQUE, array('userid', 'issuerid', 'scopehash'));
291 // Conditionally launch create table for oauth2_refresh_token.
292 if (!$dbman->table_exists($table)) {
293 $dbman->create_table($table);
296 // Main savepoint reached.
297 upgrade_main_savepoint(true, 2021052500.19);
300 if ($oldversion < 2021052500.20) {
302 // Define index modulename-instance-eventtype (not unique) to be added to event.
303 $table = new xmldb_table('event');
304 $index = new xmldb_index('modulename-instance-eventtype', XMLDB_INDEX_NOTUNIQUE, ['modulename', 'instance', 'eventtype']);
306 // Conditionally launch add index modulename-instance-eventtype.
307 if (!$dbman->index_exists($table, $index)) {
308 $dbman->add_index($table, $index);
311 // Define index modulename-instance (not unique) to be dropped form event.
312 $table = new xmldb_table('event');
313 $index = new xmldb_index('modulename-instance', XMLDB_INDEX_NOTUNIQUE, ['modulename', 'instance']);
315 // Conditionally launch drop index modulename-instance.
316 if ($dbman->index_exists($table, $index)) {
317 $dbman->drop_index($table, $index);
320 // Main savepoint reached.
321 upgrade_main_savepoint(true, 2021052500.20);
324 if ($oldversion < 2021052500.24) {
325 // Define fields tutorial and example to be added to h5p_libraries.
326 $table = new xmldb_table('h5p_libraries');
328 // Add tutorial field.
329 $field = new xmldb_field('tutorial', XMLDB_TYPE_TEXT, null, null, null, null, null, 'metadatasettings');
330 if (!$dbman->field_exists($table, $field)) {
331 $dbman->add_field($table, $field);
334 // Add example field.
335 $field = new xmldb_field('example', XMLDB_TYPE_TEXT, null, null, null, null, null, 'tutorial');
337 if (!$dbman->field_exists($table, $field)) {
338 $dbman->add_field($table, $field);
341 // Main savepoint reached.
342 upgrade_main_savepoint(true, 2021052500.24);
345 if ($oldversion < 2021052500.26) {
346 // Delete orphaned course_modules_completion rows; these were not deleted properly
347 // by remove_course_contents function.
348 $DB->delete_records_select('course_modules_completion', "
349 NOT EXISTS (
350 SELECT 1
351 FROM {course_modules} cm
352 WHERE cm.id = {course_modules_completion}.coursemoduleid
353 )");
354 upgrade_main_savepoint(true, 2021052500.26);
357 if ($oldversion < 2021052500.27) {
358 // Script to fix incorrect records of "hidden" field in existing grade items.
359 $sql = "SELECT cm.instance, cm.course
360 FROM {course_modules} cm
361 JOIN {modules} m ON m.id = cm.module
362 WHERE m.name = :module AND cm.visible = :visible";
363 $hidequizlist = $DB->get_recordset_sql($sql, ['module' => 'quiz', 'visible' => 0]);
365 foreach ($hidequizlist as $hidequiz) {
366 $params = [
367 'itemmodule' => 'quiz',
368 'courseid' => $hidequiz->course,
369 'iteminstance' => $hidequiz->instance,
372 $DB->set_field('grade_items', 'hidden', 1, $params);
374 $hidequizlist->close();
376 upgrade_main_savepoint(true, 2021052500.27);
379 if ($oldversion < 2021052500.29) {
380 // Get the current guest user which is also set as 'deleted'.
381 $guestuser = $DB->get_record('user', ['id' => $CFG->siteguest, 'deleted' => 1]);
382 // If there is a deleted guest user, reset the user to not be deleted and make sure the related
383 // user context exists.
384 if ($guestuser) {
385 $guestuser->deleted = 0;
386 $DB->update_record('user', $guestuser);
388 // Get the guest user context.
389 $guestusercontext = $DB->get_record('context',
390 ['contextlevel' => CONTEXT_USER, 'instanceid' => $guestuser->id]);
392 // If the guest user context does not exist, create it.
393 if (!$guestusercontext) {
394 $record = new stdClass();
395 $record->contextlevel = CONTEXT_USER;
396 $record->instanceid = $guestuser->id;
397 $record->depth = 0;
398 // The path is not known before insert.
399 $record->path = null;
400 $record->locked = 0;
402 $record->id = $DB->insert_record('context', $record);
404 // Update the path.
405 $record->path = '/' . SYSCONTEXTID . '/' . $record->id;
406 $record->depth = substr_count($record->path, '/');
407 $DB->update_record('context', $record);
411 // Main savepoint reached.
412 upgrade_main_savepoint(true, 2021052500.29);
415 if ($oldversion < 2021052500.30) {
416 // Reset analytics model output dir if it's the default value.
417 $modeloutputdir = get_config('analytics', 'modeloutputdir');
418 if (strcasecmp($modeloutputdir, $CFG->dataroot . DIRECTORY_SEPARATOR . 'models') == 0) {
419 set_config('modeloutputdir', '', 'analytics');
422 // Main savepoint reached.
423 upgrade_main_savepoint(true, 2021052500.30);
426 if ($oldversion < 2021052500.32) {
427 // Define field downloadcontent to be added to course.
428 $table = new xmldb_table('course');
429 $field = new xmldb_field('downloadcontent', XMLDB_TYPE_INTEGER, '1', null, null, null, null, 'visibleold');
431 if (!$dbman->field_exists($table, $field)) {
432 $dbman->add_field($table, $field);
435 // Main savepoint reached.
436 upgrade_main_savepoint(true, 2021052500.32);
439 if ($oldversion < 2021052500.33) {
440 $table = new xmldb_table('badge_backpack');
442 // There is no key_exists, so test the equivalent index.
443 $oldindex = new xmldb_index('backpackcredentials', XMLDB_KEY_UNIQUE, ['userid', 'externalbackpackid']);
444 if (!$dbman->index_exists($table, $oldindex)) {
445 // All external backpack providers/hosts are now exclusively stored in badge_external_backpack.
446 // All credentials are stored in badge_backpack and are unique per user, backpack.
447 $uniquekey = new xmldb_key('backpackcredentials', XMLDB_KEY_UNIQUE, ['userid', 'externalbackpackid']);
448 $dbman->add_key($table, $uniquekey);
451 // Drop the password field as this is moved to badge_backpack.
452 $table = new xmldb_table('badge_external_backpack');
453 $field = new xmldb_field('password', XMLDB_TYPE_CHAR, '50');
454 if ($dbman->field_exists($table, $field)) {
455 // If there is a current backpack set then copy it across to the new structure.
456 if ($CFG->badges_defaultissuercontact) {
457 // Get the currently used site backpacks.
458 $records = $DB->get_records_select('badge_external_backpack', "password IS NOT NULL AND password != ''");
459 $backpack = [
460 'userid' => '0',
461 'email' => $CFG->badges_defaultissuercontact,
462 'backpackuid' => -1
465 // Create records corresponding to the site backpacks.
466 foreach ($records as $record) {
467 $backpack['password'] = $record->password;
468 $backpack['externalbackpackid'] = $record->id;
469 $DB->insert_record('badge_backpack', (object) $backpack);
473 $dbman->drop_field($table, $field);
476 // Main savepoint reached.
477 upgrade_main_savepoint(true, 2021052500.33);
480 if ($oldversion < 2021052500.36) {
481 // Define table payment_accounts to be created.
482 $table = new xmldb_table('payment_accounts');
484 // Adding fields to table payment_accounts.
485 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
486 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
487 $table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null);
488 $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
489 $table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
490 $table->add_field('archived', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
491 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
492 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
494 // Adding keys to table payment_accounts.
495 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
497 // Conditionally launch create table for payment_accounts.
498 if (!$dbman->table_exists($table)) {
499 $dbman->create_table($table);
502 // Define table payment_gateways to be created.
503 $table = new xmldb_table('payment_gateways');
505 // Adding fields to table payment_gateways.
506 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
507 $table->add_field('accountid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
508 $table->add_field('gateway', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
509 $table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1');
510 $table->add_field('config', XMLDB_TYPE_TEXT, null, null, null, null, null);
511 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
512 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
514 // Adding keys to table payment_gateways.
515 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
516 $table->add_key('accountid', XMLDB_KEY_FOREIGN, ['accountid'], 'payment_accounts', ['id']);
518 // Conditionally launch create table for payment_gateways.
519 if (!$dbman->table_exists($table)) {
520 $dbman->create_table($table);
523 // Define table payments to be created.
524 $table = new xmldb_table('payments');
526 // Adding fields to table payments.
527 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
528 $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
529 $table->add_field('paymentarea', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, null, null);
530 $table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
531 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
532 $table->add_field('amount', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null);
533 $table->add_field('currency', XMLDB_TYPE_CHAR, '3', null, XMLDB_NOTNULL, null, null);
534 $table->add_field('accountid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
535 $table->add_field('gateway', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
536 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
537 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
539 // Adding keys to table payments.
540 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
541 $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
542 $table->add_key('accountid', XMLDB_KEY_FOREIGN, ['accountid'], 'payment_accounts', ['id']);
544 // Adding indexes to table payments.
545 $table->add_index('gateway', XMLDB_INDEX_NOTUNIQUE, ['gateway']);
546 $table->add_index('component-paymentarea-itemid', XMLDB_INDEX_NOTUNIQUE, ['component', 'paymentarea', 'itemid']);
548 // Conditionally launch create table for payments.
549 if (!$dbman->table_exists($table)) {
550 $dbman->create_table($table);
553 // Main savepoint reached.
554 upgrade_main_savepoint(true, 2021052500.36);
557 if ($oldversion < 2021052500.42) {
558 // Get all lessons that are set with a completion criteria of 'requires grade' but with no grade type set.
559 $sql = "SELECT cm.id
560 FROM {course_modules} cm
561 JOIN {lesson} l ON l.id = cm.instance
562 JOIN {modules} m ON m.id = cm.module
563 WHERE m.name = :name AND cm.completiongradeitemnumber IS NOT NULL AND l.grade = :grade";
565 do {
566 if ($invalidconfigrations = $DB->get_records_sql($sql, ['name' => 'lesson', 'grade' => 0], 0, 1000)) {
567 list($insql, $inparams) = $DB->get_in_or_equal(array_keys($invalidconfigrations), SQL_PARAMS_NAMED);
568 $DB->set_field_select('course_modules', 'completiongradeitemnumber', null, "id $insql", $inparams);
570 } while ($invalidconfigrations);
572 upgrade_main_savepoint(true, 2021052500.42);
575 if ($oldversion < 2021052500.55) {
576 $DB->delete_records_select('event', "eventtype = 'category' AND categoryid = 0 AND userid <> 0");
578 upgrade_main_savepoint(true, 2021052500.55);
581 if ($oldversion < 2021052500.59) {
582 // Define field visibility to be added to contentbank_content.
583 $table = new xmldb_table('contentbank_content');
584 $field = new xmldb_field('visibility', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'contextid');
586 // Conditionally launch add field visibility.
587 if (!$dbman->field_exists($table, $field)) {
588 $dbman->add_field($table, $field);
591 // Main savepoint reached.
592 upgrade_main_savepoint(true, 2021052500.59);
595 if ($oldversion < 2021052500.60) {
597 // We are going to remove the field 'hidepicture' from the groups
598 // so we need to remove the pictures from those groups. But we prevent
599 // the execution twice because this could be executed again when upgrading
600 // to different versions.
601 if ($dbman->field_exists('groups', 'hidepicture')) {
603 $sql = "SELECT g.id, g.courseid, ctx.id AS contextid
604 FROM {groups} g
605 JOIN {context} ctx
606 ON ctx.instanceid = g.courseid
607 AND ctx.contextlevel = :contextlevel
608 WHERE g.hidepicture = 1";
610 // Selecting all the groups that have hide picture enabled, and organising them by context.
611 $groupctx = [];
612 $records = $DB->get_recordset_sql($sql, ['contextlevel' => CONTEXT_COURSE]);
613 foreach ($records as $record) {
614 if (!isset($groupctx[$record->contextid])) {
615 $groupctx[$record->contextid] = [];
617 $groupctx[$record->contextid][] = $record->id;
619 $records->close();
621 // Deleting the group files.
622 $fs = get_file_storage();
623 foreach ($groupctx as $contextid => $groupids) {
624 list($in, $inparams) = $DB->get_in_or_equal($groupids, SQL_PARAMS_NAMED);
625 $fs->delete_area_files_select($contextid, 'group', 'icon', $in, $inparams);
628 // Updating the database to remove picture from all those groups.
629 $sql = "UPDATE {groups} SET picture = :pic WHERE hidepicture = :hide";
630 $DB->execute($sql, ['pic' => 0, 'hide' => 1]);
633 // Define field hidepicture to be dropped from groups.
634 $table = new xmldb_table('groups');
635 $field = new xmldb_field('hidepicture');
637 // Conditionally launch drop field hidepicture.
638 if ($dbman->field_exists($table, $field)) {
639 $dbman->drop_field($table, $field);
642 // Main savepoint reached.
643 upgrade_main_savepoint(true, 2021052500.60);
646 if ($oldversion < 2021052500.64) {
647 // Get all the external backpacks and update the sortorder column, to avoid repeated/wrong values. As sortorder was not
648 // used since now, the id column will be the criteria to follow for re-ordering them with a valid value.
649 $i = 1;
650 $records = $DB->get_records('badge_external_backpack', null, 'id ASC');
651 foreach ($records as $record) {
652 $record->sortorder = $i++;
653 $DB->update_record('badge_external_backpack', $record);
656 upgrade_main_savepoint(true, 2021052500.64);
659 if ($oldversion < 2021052500.67) {
660 // The $CFG->badges_site_backpack setting has been removed because it's not required anymore. From now, the default backpack
661 // will be the one with lower sortorder value.
662 unset_config('badges_site_backpack');
664 upgrade_main_savepoint(true, 2021052500.67);
667 if ($oldversion < 2021052500.69) {
669 // Define field type to be added to oauth2_issuer.
670 $table = new xmldb_table('oauth2_issuer');
671 $field = new xmldb_field('servicetype', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'requireconfirmation');
673 // Conditionally launch add field type.
674 if (!$dbman->field_exists($table, $field)) {
675 $dbman->add_field($table, $field);
678 // Set existing values to the proper servicetype value.
679 // It's not critical if the servicetype column doesn't contain the proper value for Google, Microsoft, Facebook or
680 // Nextcloud services because, for now, this value is used for services using different discovery method.
681 // However, let's try to upgrade it using the default value for the baseurl or image. If any of these default values
682 // have been changed, the servicetype column will remain NULL.
683 $recordset = $DB->get_recordset('oauth2_issuer');
684 foreach ($recordset as $record) {
685 if ($record->baseurl == 'https://accounts.google.com/') {
686 $record->servicetype = 'google';
687 $DB->update_record('oauth2_issuer', $record);
688 } else if ($record->image == 'https://www.microsoft.com/favicon.ico') {
689 $record->servicetype = 'microsoft';
690 $DB->update_record('oauth2_issuer', $record);
691 } else if ($record->image == 'https://facebookbrand.com/wp-content/uploads/2016/05/flogo_rgb_hex-brc-site-250.png') {
692 $record->servicetype = 'facebook';
693 $DB->update_record('oauth2_issuer', $record);
694 } else if ($record->image == 'https://nextcloud.com/wp-content/themes/next/assets/img/common/favicon.png?x16328') {
695 $record->servicetype = 'nextcloud';
696 $DB->update_record('oauth2_issuer', $record);
699 $recordset->close();
701 // Main savepoint reached.
702 upgrade_main_savepoint(true, 2021052500.69);
705 if ($oldversion < 2021052500.74) {
706 // Define field 'showactivitydates' to be added to course table.
707 $table = new xmldb_table('course');
708 $field = new xmldb_field('showactivitydates', XMLDB_TYPE_INTEGER, '1', null,
709 XMLDB_NOTNULL, null, '0', 'originalcourseid');
711 if (!$dbman->field_exists($table, $field)) {
712 $dbman->add_field($table, $field);
715 // Main savepoint reached.
716 upgrade_main_savepoint(true, 2021052500.74);
719 if ($oldversion < 2021052500.75) {
720 // Define field 'showcompletionconditions' to be added to course.
721 $table = new xmldb_table('course');
722 $field = new xmldb_field('showcompletionconditions', XMLDB_TYPE_INTEGER, '1', null,
723 XMLDB_NOTNULL, null, '1', 'completionnotify');
725 if (!$dbman->field_exists($table, $field)) {
726 $dbman->add_field($table, $field);
729 // Main savepoint reached.
730 upgrade_main_savepoint(true, 2021052500.75);
733 if ($oldversion < 2021052500.78) {
735 // Define field enabled to be added to h5p_libraries.
736 $table = new xmldb_table('h5p_libraries');
737 $field = new xmldb_field('enabled', XMLDB_TYPE_INTEGER, '1', null, null, null, '1', 'example');
739 // Conditionally launch add field enabled.
740 if (!$dbman->field_exists($table, $field)) {
741 $dbman->add_field($table, $field);
744 // Main savepoint reached.
745 upgrade_main_savepoint(true, 2021052500.78);
748 if ($oldversion < 2021052500.83) {
750 // Define field loginpagename to be added to oauth2_issuer.
751 $table = new xmldb_table('oauth2_issuer');
752 $field = new xmldb_field('loginpagename', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'servicetype');
754 // Conditionally launch add field loginpagename.
755 if (!$dbman->field_exists($table, $field)) {
756 $dbman->add_field($table, $field);
759 // Main savepoint reached.
760 upgrade_main_savepoint(true, 2021052500.83);
763 if ($oldversion < 2021052500.84) {
764 require_once($CFG->dirroot . '/user/profile/field/social/upgradelib.php');
765 $table = new xmldb_table('user');
766 $tablecolumns = ['icq', 'skype', 'aim', 'yahoo', 'msn', 'url'];
768 foreach ($tablecolumns as $column) {
769 $field = new xmldb_field($column);
770 if ($dbman->field_exists($table, $field)) {
771 user_profile_social_moveto_profilefield($column);
772 $dbman->drop_field($table, $field);
776 // Update all module availability if it relies on the old user fields.
777 user_profile_social_update_module_availability();
779 // Remove field mapping for oauth2.
780 $DB->delete_records('oauth2_user_field_mapping', array('internalfield' => 'url'));
782 // Main savepoint reached.
783 upgrade_main_savepoint(true, 2021052500.84);
786 if ($oldversion < 2021052500.85) {
787 require_once($CFG->libdir . '/db/upgradelib.php');
789 // Check if this site has executed the problematic upgrade steps.
790 $needsfixing = upgrade_calendar_site_status(false);
792 // Only queue the task if this site has been affected by the problematic upgrade step.
793 if ($needsfixing) {
795 // Create adhoc task to search and recover orphaned calendar events.
796 $record = new \stdClass();
797 $record->classname = '\core\task\calendar_fix_orphaned_events';
799 // Next run time based from nextruntime computation in \core\task\manager::queue_adhoc_task().
800 $nextruntime = time() - 1;
801 $record->nextruntime = $nextruntime;
802 $DB->insert_record('task_adhoc', $record);
805 // Main savepoint reached.
806 upgrade_main_savepoint(true, 2021052500.85);
809 if ($oldversion < 2021052500.87) {
810 // Changing the default of field showcompletionconditions on table course to 0.
811 $table = new xmldb_table('course');
812 $field = new xmldb_field('showcompletionconditions', XMLDB_TYPE_INTEGER, '1', null, null, null, null, 'showactivitydates');
814 // Launch change of nullability for field showcompletionconditions.
815 $dbman->change_field_notnull($table, $field);
817 // Launch change of default for field showcompletionconditions.
818 $dbman->change_field_default($table, $field);
820 // Set showcompletionconditions to null for courses which don't track completion.
821 $sql = "UPDATE {course}
822 SET showcompletionconditions = null
823 WHERE enablecompletion <> 1";
824 $DB->execute($sql);
826 // Main savepoint reached.
827 upgrade_main_savepoint(true, 2021052500.87);
830 if ($oldversion < 2021052500.90) {
831 // Remove usemodchooser user preference for every user.
832 $DB->delete_records('user_preferences', ['name' => 'usemodchooser']);
834 // Main savepoint reached.
835 upgrade_main_savepoint(true, 2021052500.90);
838 if ($oldversion < 2021060200.00) {
840 // Define index name (not unique) to be added to user_preferences.
841 $table = new xmldb_table('user_preferences');
842 $index = new xmldb_index('name', XMLDB_INDEX_NOTUNIQUE, ['name']);
844 // Conditionally launch add index name.
845 if (!$dbman->index_exists($table, $index)) {
846 $dbman->add_index($table, $index);
849 // Main savepoint reached.
850 upgrade_main_savepoint(true, 2021060200.00);
853 if ($oldversion < 2021060900.00) {
854 // Update the externalfield to be larger.
855 $table = new xmldb_table('oauth2_user_field_mapping');
856 $field = new xmldb_field('externalfield', XMLDB_TYPE_CHAR, '500', null, XMLDB_NOTNULL, false, null, 'issuerid');
857 $dbman->change_field_type($table, $field);
859 // Main savepoint reached.
860 upgrade_main_savepoint(true, 2021060900.00);
863 if ($oldversion < 2021072800.01) {
864 // Define table reportbuilder_report to be created.
865 $table = new xmldb_table('reportbuilder_report');
867 // Adding fields to table reportbuilder_report.
868 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
869 $table->add_field('source', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
870 $table->add_field('type', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
871 $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
872 $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
873 $table->add_field('area', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
874 $table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
875 $table->add_field('usercreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
876 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
877 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
878 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
880 // Adding keys to table reportbuilder_report.
881 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
882 $table->add_key('usercreated', XMLDB_KEY_FOREIGN, ['usercreated'], 'user', ['id']);
883 $table->add_key('usermodified', XMLDB_KEY_FOREIGN, ['usermodified'], 'user', ['id']);
884 $table->add_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']);
886 // Conditionally launch create table for reportbuilder_report.
887 if (!$dbman->table_exists($table)) {
888 $dbman->create_table($table);
891 // Main savepoint reached.
892 upgrade_main_savepoint(true, 2021072800.01);
895 if ($oldversion < 2021090200.01) {
896 // Remove qformat_webct (unless it has manually been added back).
897 if (!file_exists($CFG->dirroot . '/question/format/webct/format.php')) {
898 unset_all_config_for_plugin('qformat_webct');
901 // Main savepoint reached.
902 upgrade_main_savepoint(true, 2021090200.01);
905 if ($oldversion < 2021091100.01) {
906 // If message_jabber is no longer present, remove it.
907 if (!file_exists($CFG->dirroot . '/message/output/jabber/message_output_jabber.php')) {
908 // Remove Jabber from the notification plugins list.
909 $DB->delete_records('message_processors', ['name' => 'jabber']);
911 // Remove user preference settings.
912 $DB->delete_records('user_preferences', ['name' => 'message_processor_jabber_jabberid']);
913 $sql = 'SELECT *
914 FROM {user_preferences} up
915 WHERE ' . $DB->sql_like('up.name', ':name', false, false) . ' AND ' .
916 $DB->sql_like('up.value', ':value', false, false);
917 $params = [
918 'name' => 'message_provider_%',
919 'value' => '%jabber%',
921 $jabbersettings = $DB->get_recordset_sql($sql, $params);
922 foreach ($jabbersettings as $jabbersetting) {
923 // Remove 'jabber' from the value.
924 $jabbersetting->value = implode(',', array_diff(explode(',', $jabbersetting->value), ['jabber']));
925 $DB->update_record('user_preferences', $jabbersetting);
927 $jabbersettings->close();
929 // Clean config settings.
930 unset_config('jabberhost');
931 unset_config('jabberserver');
932 unset_config('jabberusername');
933 unset_config('jabberpassword');
934 unset_config('jabberport');
936 // Remove default notification preferences.
937 $like = $DB->sql_like('name', '?', true, true, false, '|');
938 $params = [$DB->sql_like_escape('jabber_provider_', '|') . '%'];
939 $DB->delete_records_select('config_plugins', $like, $params);
941 // Clean config config settings.
942 unset_all_config_for_plugin('message_jabber');
945 upgrade_main_savepoint(true, 2021091100.01);
948 if ($oldversion < 2021091100.02) {
949 // Set the description field to HTML format for the Default course category.
950 $category = $DB->get_record('course_categories', ['id' => 1]);
952 if (!empty($category) && $category->descriptionformat == FORMAT_MOODLE) {
953 // Format should be changed only if it's still set to FORMAT_MOODLE.
954 if (!is_null($category->description)) {
955 // If description is not empty, format the content to HTML.
956 $category->description = format_text($category->description, FORMAT_MOODLE);
958 $category->descriptionformat = FORMAT_HTML;
959 $DB->update_record('course_categories', $category);
962 // Main savepoint reached.
963 upgrade_main_savepoint(true, 2021091100.02);
966 if ($oldversion < 2021091700.01) {
967 // Default 'off' for existing sites as this is the behaviour they had earlier.
968 set_config('enroladminnewcourse', false);
970 // Main savepoint reached.
971 upgrade_main_savepoint(true, 2021091700.01);
974 if ($oldversion < 2021091700.02) {
975 // If portfolio_picasa is no longer present, remove it.
976 if (!file_exists($CFG->dirroot . '/portfolio/picasa/version.php')) {
977 $instance = $DB->get_record('portfolio_instance', ['plugin' => 'picasa']);
978 if (!empty($instance)) {
979 // Remove all records from portfolio_instance_config.
980 $DB->delete_records('portfolio_instance_config', ['instance' => $instance->id]);
981 // Remove all records from portfolio_instance_user.
982 $DB->delete_records('portfolio_instance_user', ['instance' => $instance->id]);
983 // Remove all records from portfolio_log.
984 $DB->delete_records('portfolio_log', ['portfolio' => $instance->id]);
985 // Remove all records from portfolio_tempdata.
986 $DB->delete_records('portfolio_tempdata', ['instance' => $instance->id]);
987 // Remove the record from the portfolio_instance table.
988 $DB->delete_records('portfolio_instance', ['id' => $instance->id]);
991 // Clean config.
992 unset_all_config_for_plugin('portfolio_picasa');
995 upgrade_main_savepoint(true, 2021091700.02);
998 if ($oldversion < 2021091700.03) {
999 // If repository_picasa is no longer present, remove it.
1000 if (!file_exists($CFG->dirroot . '/repository/picasa/version.php')) {
1001 $instance = $DB->get_record('repository', ['type' => 'picasa']);
1002 if (!empty($instance)) {
1003 // Remove all records from repository_instance_config table.
1004 $DB->delete_records('repository_instance_config', ['instanceid' => $instance->id]);
1005 // Remove all records from repository_instances table.
1006 $DB->delete_records('repository_instances', ['typeid' => $instance->id]);
1007 // Remove the record from the repository table.
1008 $DB->delete_records('repository', ['id' => $instance->id]);
1011 // Clean config.
1012 unset_all_config_for_plugin('picasa');
1014 // Remove orphaned files.
1015 upgrade_delete_orphaned_file_records();
1018 upgrade_main_savepoint(true, 2021091700.03);
1021 if ($oldversion < 2021091700.04) {
1022 // Remove media_swf (unless it has manually been added back).
1023 if (!file_exists($CFG->dirroot . '/media/player/swf/classes/plugin.php')) {
1024 unset_all_config_for_plugin('media_swf');
1027 upgrade_main_savepoint(true, 2021091700.04);
1030 if ($oldversion < 2021092400.01) {
1031 // If tool_health is no longer present, remove it.
1032 if (!file_exists($CFG->dirroot . '/admin/tool/health/version.php')) {
1033 // Clean config.
1034 unset_all_config_for_plugin('tool_health');
1037 // Main savepoint reached.
1038 upgrade_main_savepoint(true, 2021092400.01);
1041 if ($oldversion < 2021092400.03) {
1042 // Remove repository_picasa configuration (unless it has manually been added back).
1043 if (!file_exists($CFG->dirroot . '/repository/picasa/version.php')) {
1044 unset_all_config_for_plugin('repository_picasa');
1047 upgrade_main_savepoint(true, 2021092400.03);
1050 if ($oldversion < 2021100300.01) {
1051 // Remove repository_skydrive (unless it has manually been added back).
1052 if (!file_exists($CFG->dirroot . '/repository/skydrive/lib.php')) {
1053 unset_all_config_for_plugin('repository_skydrive');
1056 // Main savepoint reached.
1057 upgrade_main_savepoint(true, 2021100300.01);
1060 if ($oldversion < 2021100300.02) {
1061 // Remove filter_censor (unless it has manually been added back).
1062 if (!file_exists($CFG->dirroot . '/filter/censor/filter.php')) {
1063 unset_all_config_for_plugin('filter_censor');
1066 // Main savepoint reached.
1067 upgrade_main_savepoint(true, 2021100300.02);
1070 if ($oldversion < 2021100600.01) {
1071 // Remove qformat_examview (unless it has manually been added back).
1072 if (!file_exists($CFG->dirroot . '/question/format/examview/format.php')) {
1073 unset_all_config_for_plugin('qformat_examview');
1076 // Main savepoint reached.
1077 upgrade_main_savepoint(true, 2021100600.01);
1080 if ($oldversion < 2021100600.02) {
1081 $table = new xmldb_table('course_completion_defaults');
1083 // Adding fields to table course_completion_defaults.
1084 $field = new xmldb_field('completionpassgrade', XMLDB_TYPE_INTEGER, '1', null,
1085 XMLDB_NOTNULL, null, '0', 'completionusegrade');
1087 // Conditionally launch add field for course_completion_defaults.
1088 if (!$dbman->field_exists($table, $field)) {
1089 $dbman->add_field($table, $field);
1092 upgrade_main_savepoint(true, 2021100600.02);
1095 if ($oldversion < 2021100600.03) {
1096 $table = new xmldb_table('course_modules');
1098 // Adding new fields to table course_module table.
1099 $field = new xmldb_field('completionpassgrade', XMLDB_TYPE_INTEGER, '1', null,
1100 XMLDB_NOTNULL, null, '0', 'completionexpected');
1101 // Conditionally launch create table for course_completion_defaults.
1102 if (!$dbman->field_exists($table, $field)) {
1103 $dbman->add_field($table, $field);
1106 upgrade_main_savepoint(true, 2021100600.03);
1109 if ($oldversion < 2021100600.04) {
1110 // Define index itemtype-mod-inst-course (not unique) to be added to grade_items.
1111 $table = new xmldb_table('grade_items');
1112 $index = new xmldb_index('itemtype-mod-inst-course', XMLDB_INDEX_NOTUNIQUE,
1113 ['itemtype', 'itemmodule', 'iteminstance', 'courseid']);
1115 // Conditionally launch add index itemtype-mod-inst-course.
1116 if (!$dbman->index_exists($table, $index)) {
1117 $dbman->add_index($table, $index);
1120 // Main savepoint reached.
1121 upgrade_main_savepoint(true, 2021100600.04);
1124 if ($oldversion < 2021101900.01) {
1125 $table = new xmldb_table('reportbuilder_report');
1127 // Define field name to be added to reportbuilder_report.
1128 $field = new xmldb_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'id');
1129 if (!$dbman->field_exists($table, $field)) {
1130 $dbman->add_field($table, $field);
1133 // Define field conditiondata to be added to reportbuilder_report.
1134 $field = new xmldb_field('conditiondata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'type');
1135 if (!$dbman->field_exists($table, $field)) {
1136 $dbman->add_field($table, $field);
1139 // Define table reportbuilder_column to be created.
1140 $table = new xmldb_table('reportbuilder_column');
1142 // Adding fields to table reportbuilder_column.
1143 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1144 $table->add_field('reportid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1145 $table->add_field('uniqueidentifier', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1146 $table->add_field('aggregation', XMLDB_TYPE_CHAR, '32', null, null, null, null);
1147 $table->add_field('heading', XMLDB_TYPE_CHAR, '255', null, null, null, null);
1148 $table->add_field('columnorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1149 $table->add_field('sortenabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
1150 $table->add_field('sortdirection', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, null);
1151 $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
1152 $table->add_field('usercreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1153 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1154 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1155 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1157 // Adding keys to table reportbuilder_column.
1158 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1159 $table->add_key('reportid', XMLDB_KEY_FOREIGN, ['reportid'], 'reportbuilder_report', ['id']);
1160 $table->add_key('usercreated', XMLDB_KEY_FOREIGN, ['usercreated'], 'user', ['id']);
1161 $table->add_key('usermodified', XMLDB_KEY_FOREIGN, ['usermodified'], 'user', ['id']);
1163 // Conditionally launch create table for reportbuilder_column.
1164 if (!$dbman->table_exists($table)) {
1165 $dbman->create_table($table);
1168 // Define table reportbuilder_filter to be created.
1169 $table = new xmldb_table('reportbuilder_filter');
1171 // Adding fields to table reportbuilder_filter.
1172 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1173 $table->add_field('reportid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1174 $table->add_field('uniqueidentifier', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1175 $table->add_field('heading', XMLDB_TYPE_CHAR, '255', null, null, null, null);
1176 $table->add_field('iscondition', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
1177 $table->add_field('filterorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1178 $table->add_field('usercreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1179 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1180 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1181 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1183 // Adding keys to table reportbuilder_filter.
1184 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1185 $table->add_key('reportid', XMLDB_KEY_FOREIGN, ['reportid'], 'reportbuilder_report', ['id']);
1186 $table->add_key('usercreated', XMLDB_KEY_FOREIGN, ['usercreated'], 'user', ['id']);
1187 $table->add_key('usermodified', XMLDB_KEY_FOREIGN, ['usermodified'], 'user', ['id']);
1189 // Conditionally launch create table for reportbuilder_filter.
1190 if (!$dbman->table_exists($table)) {
1191 $dbman->create_table($table);
1194 // Main savepoint reached.
1195 upgrade_main_savepoint(true, 2021101900.01);
1198 if ($oldversion < 2021102600.01) {
1199 // Remove block_quiz_results (unless it has manually been added back).
1200 if (!file_exists($CFG->dirroot . '/blocks/quiz_result/block_quiz_results.php')) {
1201 // Delete instances.
1202 $instances = $DB->get_records_list('block_instances', 'blockname', ['quiz_results']);
1203 $instanceids = array_keys($instances);
1205 if (!empty($instanceids)) {
1206 blocks_delete_instances($instanceids);
1209 // Delete the block from the block table.
1210 $DB->delete_records('block', array('name' => 'quiz_results'));
1212 // Remove capabilities.
1213 capabilities_cleanup('block_quiz_results');
1214 // Clean config.
1215 unset_all_config_for_plugin('block_quiz_results');
1217 // Remove Moodle-level quiz_results based capabilities.
1218 $capabilitiestoberemoved = ['block/quiz_results:addinstance'];
1219 // Delete any role_capabilities for the old roles.
1220 $DB->delete_records_list('role_capabilities', 'capability', $capabilitiestoberemoved);
1221 // Delete the capability itself.
1222 $DB->delete_records_list('capabilities', 'name', $capabilitiestoberemoved);
1225 upgrade_main_savepoint(true, 2021102600.01);
1228 if ($oldversion < 2021102900.02) {
1229 // If portfolio_boxnet is no longer present, remove it.
1230 if (!file_exists($CFG->dirroot . '/portfolio/boxnet/version.php')) {
1231 $instance = $DB->get_record('portfolio_instance', ['plugin' => 'boxnet']);
1232 if (!empty($instance)) {
1233 // Remove all records from portfolio_instance_config.
1234 $DB->delete_records('portfolio_instance_config', ['instance' => $instance->id]);
1235 // Remove all records from portfolio_instance_user.
1236 $DB->delete_records('portfolio_instance_user', ['instance' => $instance->id]);
1237 // Remove all records from portfolio_log.
1238 $DB->delete_records('portfolio_log', ['portfolio' => $instance->id]);
1239 // Remove all records from portfolio_tempdata.
1240 $DB->delete_records('portfolio_tempdata', ['instance' => $instance->id]);
1241 // Remove the record from the portfolio_instance table.
1242 $DB->delete_records('portfolio_instance', ['id' => $instance->id]);
1245 // Clean config.
1246 unset_all_config_for_plugin('portfolio_boxnet');
1249 // If repository_boxnet is no longer present, remove it.
1250 if (!file_exists($CFG->dirroot . '/repository/boxnet/version.php')) {
1251 $instance = $DB->get_record('repository', ['type' => 'boxnet']);
1252 if (!empty($instance)) {
1253 // Remove all records from repository_instance_config table.
1254 $DB->delete_records('repository_instance_config', ['instanceid' => $instance->id]);
1255 // Remove all records from repository_instances table.
1256 $DB->delete_records('repository_instances', ['typeid' => $instance->id]);
1257 // Remove the record from the repository table.
1258 $DB->delete_records('repository', ['id' => $instance->id]);
1261 // Clean config.
1262 unset_all_config_for_plugin('repository_boxnet');
1264 // The boxnet repository plugin stores some config in 'boxnet' incorrectly.
1265 unset_all_config_for_plugin('boxnet');
1267 // Remove orphaned files.
1268 upgrade_delete_orphaned_file_records();
1271 upgrade_main_savepoint(true, 2021102900.02);
1274 if ($oldversion < 2021110100.00) {
1276 // Define table reportbuilder_audience to be created.
1277 $table = new xmldb_table('reportbuilder_audience');
1279 // Adding fields to table reportbuilder_audience.
1280 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1281 $table->add_field('reportid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1282 $table->add_field('classname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1283 $table->add_field('configdata', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
1284 $table->add_field('usercreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1285 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1286 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1287 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1289 // Adding keys to table reportbuilder_audience.
1290 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1291 $table->add_key('reportid', XMLDB_KEY_FOREIGN, ['reportid'], 'reportbuilder_report', ['id']);
1292 $table->add_key('usercreated', XMLDB_KEY_FOREIGN, ['usercreated'], 'user', ['id']);
1293 $table->add_key('usermodified', XMLDB_KEY_FOREIGN, ['usermodified'], 'user', ['id']);
1295 // Conditionally launch create table for reportbuilder_audience.
1296 if (!$dbman->table_exists($table)) {
1297 $dbman->create_table($table);
1300 // Main savepoint reached.
1301 upgrade_main_savepoint(true, 2021110100.00);
1304 if ($oldversion < 2021110800.02) {
1305 // Define a field 'downloadcontent' in the 'course_modules' table.
1306 $table = new xmldb_table('course_modules');
1307 $field = new xmldb_field('downloadcontent', XMLDB_TYPE_INTEGER, '1', null, null, null, 1, 'deletioninprogress');
1309 // Conditionally launch add field 'downloadcontent'.
1310 if (!$dbman->field_exists($table, $field)) {
1311 $dbman->add_field($table, $field);
1314 // Main savepoint reached.
1315 upgrade_main_savepoint(true, 2021110800.02);
1318 if ($oldversion < 2021110800.03) {
1320 // Define field settingsdata to be added to reportbuilder_report.
1321 $table = new xmldb_table('reportbuilder_report');
1322 $field = new xmldb_field('settingsdata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'conditiondata');
1324 // Conditionally launch add field settingsdata.
1325 if (!$dbman->field_exists($table, $field)) {
1326 $dbman->add_field($table, $field);
1329 // Main savepoint reached.
1330 upgrade_main_savepoint(true, 2021110800.03);
1333 if ($oldversion < 2021111700.00) {
1334 $mycoursespage = new stdClass();
1335 $mycoursespage->userid = null;
1336 $mycoursespage->name = '__courses';
1337 $mycoursespage->private = 0;
1338 $mycoursespage->sortorder = 0;
1339 $DB->insert_record('my_pages', $mycoursespage);
1341 upgrade_main_savepoint(true, 2021111700.00);
1344 if ($oldversion < 2021111700.01) {
1346 // Define field uniquerows to be added to reportbuilder_report.
1347 $table = new xmldb_table('reportbuilder_report');
1348 $field = new xmldb_field('uniquerows', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'type');
1350 // Conditionally launch add field uniquerows.
1351 if (!$dbman->field_exists($table, $field)) {
1352 $dbman->add_field($table, $field);
1355 // Main savepoint reached.
1356 upgrade_main_savepoint(true, 2021111700.01);
1359 if ($oldversion < 2021120100.01) {
1361 // Get current configuration data.
1362 $currentcustomusermenuitems = str_replace(["\r\n", "\r"], "\n", $CFG->customusermenuitems);
1363 $lines = explode("\n", $currentcustomusermenuitems);
1364 $lines = array_map('trim', $lines);
1365 $calendarcustomusermenu = 'calendar,core_calendar|/calendar/view.php?view=month|i/calendar';
1367 if (!in_array($calendarcustomusermenu, $lines)) {
1368 // Add Calendar item to the menu.
1369 array_splice($lines, 1, 0, [$calendarcustomusermenu]);
1370 set_config('customusermenuitems', implode("\n", $lines));
1373 // Main savepoint reached.
1374 upgrade_main_savepoint(true, 2021120100.01);
1377 if ($oldversion < 2021121400.01) {
1378 // The $CFG->grade_navmethod setting has been removed because it's not required anymore. This setting was used
1379 // to set the type of navigation (tabs or dropdown box) which will be displayed in gradebook. However, these
1380 // navigation methods are no longer used and replaced with tertiary navigation.
1381 unset_config('grade_navmethod');
1383 // Main savepoint reached.
1384 upgrade_main_savepoint(true, 2021121400.01);
1387 if ($oldversion < 2021121700.01) {
1388 // Get current support email setting value.
1389 $config = get_config('moodle', 'supportemail');
1391 // Check if support email setting is empty and then set it to null.
1392 // We must do that so the setting is displayed during the upgrade.
1393 if (empty($config)) {
1394 set_config('supportemail', null);
1397 // Main savepoint reached.
1398 upgrade_main_savepoint(true, 2021121700.01);
1401 if ($oldversion < 2021122100.00) {
1402 // Get current configuration data.
1403 $currentcustomusermenuitems = str_replace(["\r\n", "\r"], "\n", $CFG->customusermenuitems);
1405 // The old default customusermenuitems config for 3.11 and below.
1406 $oldcustomusermenuitems = 'grades,grades|/grade/report/mygrades.php|t/grades
1407 calendar,core_calendar|/calendar/view.php?view=month|i/calendar
1408 messages,message|/message/index.php|t/message
1409 preferences,moodle|/user/preferences.php|t/preferences';
1411 // Check if the current customusermenuitems config matches the old customusermenuitems config.
1412 $samecustomusermenuitems = $currentcustomusermenuitems == $oldcustomusermenuitems;
1413 if ($samecustomusermenuitems) {
1414 // If the site is still using the old defaults, upgrade to the new default.
1415 $newcustomusermenuitems = 'profile,moodle|/user/profile.php
1416 grades,grades|/grade/report/mygrades.php
1417 calendar,core_calendar|/calendar/view.php?view=month
1418 privatefiles,moodle|/user/files.php';
1419 // Set the new configuration back.
1420 set_config('customusermenuitems', $newcustomusermenuitems);
1421 } else {
1422 // If the site is not using the old defaults, only add necessary entries.
1423 $lines = preg_split('/\n/', $currentcustomusermenuitems, -1, PREG_SPLIT_NO_EMPTY);
1424 $lines = array_map(static function(string $line): string {
1425 // Previous format was "<langstring>|<url>[|<pixicon>]" - pix icon is no longer supported.
1426 $lineparts = explode('|', trim($line), 3);
1427 // Return first two parts of line.
1428 return implode('|', array_slice($lineparts, 0, 2));
1429 }, $lines);
1431 // Remove the Preference entry from the menu to prevent duplication
1432 // since it will be added again in user_get_user_navigation_info().
1433 $lines = array_filter($lines, function($value) {
1434 return strpos($value, 'preferences,moodle|/user/preferences.php') === false;
1437 $matches = preg_grep('/\|\/user\/files.php/i', $lines);
1438 if (!$matches) {
1439 // Add the Private files entry to the menu.
1440 $lines[] = 'privatefiles,moodle|/user/files.php';
1443 $matches = preg_grep('/\|\/user\/profile.php/i', $lines);
1444 if (!$matches) {
1445 // Add the Profile entry to top of the menu.
1446 array_unshift($lines, 'profile,moodle|/user/profile.php');
1449 // Set the new configuration back.
1450 set_config('customusermenuitems', implode("\n", $lines));
1453 // Main savepoint reached.
1454 upgrade_main_savepoint(true, 2021122100.00);
1458 if ($oldversion < 2021122100.01) {
1460 // Define field heading to be added to reportbuilder_audience.
1461 $table = new xmldb_table('reportbuilder_audience');
1462 $field = new xmldb_field('heading', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'reportid');
1464 // Conditionally launch add field heading.
1465 if (!$dbman->field_exists($table, $field)) {
1466 $dbman->add_field($table, $field);
1469 // Main savepoint reached.
1470 upgrade_main_savepoint(true, 2021122100.01);
1473 if ($oldversion < 2021122100.02) {
1475 // Define table reportbuilder_schedule to be created.
1476 $table = new xmldb_table('reportbuilder_schedule');
1478 // Adding fields to table reportbuilder_schedule.
1479 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1480 $table->add_field('reportid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1481 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1482 $table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1');
1483 $table->add_field('audiences', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
1484 $table->add_field('format', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1485 $table->add_field('subject', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1486 $table->add_field('message', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
1487 $table->add_field('messageformat', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1488 $table->add_field('userviewas', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1489 $table->add_field('timescheduled', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1490 $table->add_field('recurrence', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1491 $table->add_field('reportempty', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1492 $table->add_field('timelastsent', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1493 $table->add_field('timenextsend', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1494 $table->add_field('usercreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1495 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1496 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1497 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1499 // Adding keys to table reportbuilder_schedule.
1500 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1501 $table->add_key('reportid', XMLDB_KEY_FOREIGN, ['reportid'], 'reportbuilder_report', ['id']);
1502 $table->add_key('userviewas', XMLDB_KEY_FOREIGN, ['userviewas'], 'user', ['id']);
1503 $table->add_key('usercreated', XMLDB_KEY_FOREIGN, ['usercreated'], 'user', ['id']);
1504 $table->add_key('usermodified', XMLDB_KEY_FOREIGN, ['usermodified'], 'user', ['id']);
1506 // Conditionally launch create table for reportbuilder_schedule.
1507 if (!$dbman->table_exists($table)) {
1508 $dbman->create_table($table);
1511 // Main savepoint reached.
1512 upgrade_main_savepoint(true, 2021122100.02);
1515 if ($oldversion < 2021123000.01) {
1516 // The tool_admin_presets tables have been moved to core, because core_adminpresets component has been created, so
1517 // it can interact with the rest of core.
1518 // So the tool_admin_presetsXXX tables will be renamed to adminipresetsXXX if they exists; otherwise, they will be created.
1520 $tooltable = new xmldb_table('tool_admin_presets');
1521 $table = new xmldb_table('adminpresets');
1522 if ($dbman->table_exists($tooltable)) {
1523 $dbman->rename_table($tooltable, 'adminpresets');
1524 } else if (!$dbman->table_exists($table)) {
1525 // Adding fields to table adminpresets.
1526 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1527 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1528 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1529 $table->add_field('comments', XMLDB_TYPE_TEXT, null, null, null, null, null);
1530 $table->add_field('site', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1531 $table->add_field('author', XMLDB_TYPE_CHAR, '255', null, null, null, null);
1532 $table->add_field('moodleversion', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null);
1533 $table->add_field('moodlerelease', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1534 $table->add_field('iscore', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
1535 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1536 $table->add_field('timeimported', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1538 // Adding keys to table adminpresets.
1539 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1541 // Launch create table for adminpresets.
1542 $dbman->create_table($table);
1545 $tooltable = new xmldb_table('tool_admin_presets_it');
1546 $table = new xmldb_table('adminpresets_it');
1547 if ($dbman->table_exists($tooltable)) {
1548 $dbman->rename_table($tooltable, 'adminpresets_it');
1549 } else if (!$dbman->table_exists($table)) {
1550 // Adding fields to table adminpresets_it.
1551 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1552 $table->add_field('adminpresetid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1553 $table->add_field('plugin', XMLDB_TYPE_CHAR, '100', null, null, null, null);
1554 $table->add_field('name', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
1555 $table->add_field('value', XMLDB_TYPE_TEXT, null, null, null, null, null);
1557 // Adding keys to table adminpresets_it.
1558 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1560 // Adding indexes to table adminpresets_it.
1561 $table->add_index('adminpresetid', XMLDB_INDEX_NOTUNIQUE, ['adminpresetid']);
1563 // Launch create table for adminpresets_it.
1564 $dbman->create_table($table);
1567 $tooltable = new xmldb_table('tool_admin_presets_it_a');
1568 $table = new xmldb_table('adminpresets_it_a');
1569 if ($dbman->table_exists($tooltable)) {
1570 $dbman->rename_table($tooltable, 'adminpresets_it_a');
1571 } else if (!$dbman->table_exists($table)) {
1572 // Adding fields to table adminpresets_it_a.
1573 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1574 $table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1575 $table->add_field('name', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
1576 $table->add_field('value', XMLDB_TYPE_TEXT, null, null, null, null, null);
1578 // Adding keys to table adminpresets_it_a.
1579 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1581 // Adding indexes to table adminpresets_it_a.
1582 $table->add_index('itemid', XMLDB_INDEX_NOTUNIQUE, ['itemid']);
1584 // Launch create table for adminpresets_it_a.
1585 $dbman->create_table($table);
1588 $tooltable = new xmldb_table('tool_admin_presets_app');
1589 $table = new xmldb_table('adminpresets_app');
1590 if ($dbman->table_exists($tooltable)) {
1591 $dbman->rename_table($tooltable, 'adminpresets_app');
1592 } else if (!$dbman->table_exists($table)) {
1593 // Adding fields to table adminpresets_app.
1594 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1595 $table->add_field('adminpresetid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1596 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1597 $table->add_field('time', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1599 // Adding keys to table adminpresets_app.
1600 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1602 // Adding indexes to table adminpresets_app.
1603 $table->add_index('adminpresetid', XMLDB_INDEX_NOTUNIQUE, ['adminpresetid']);
1605 // Launch create table for adminpresets_app.
1606 $dbman->create_table($table);
1609 $tooltable = new xmldb_table('tool_admin_presets_app_it');
1610 $table = new xmldb_table('adminpresets_app_it');
1611 if ($dbman->table_exists($tooltable)) {
1612 $dbman->rename_table($tooltable, 'adminpresets_app_it');
1613 } else if (!$dbman->table_exists($table)) {
1614 // Adding fields to table adminpresets_app_it.
1615 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1616 $table->add_field('adminpresetapplyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1617 $table->add_field('configlogid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1619 // Adding keys to table adminpresets_app_it.
1620 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1622 // Adding indexes to table adminpresets_app_it.
1623 $table->add_index('configlogid', XMLDB_INDEX_NOTUNIQUE, ['configlogid']);
1624 $table->add_index('adminpresetapplyid', XMLDB_INDEX_NOTUNIQUE, ['adminpresetapplyid']);
1626 // Launch create table for adminpresets_app_it.
1627 $dbman->create_table($table);
1630 $tooltable = new xmldb_table('tool_admin_presets_app_it_a');
1631 $table = new xmldb_table('adminpresets_app_it_a');
1632 if ($dbman->table_exists($tooltable)) {
1633 $dbman->rename_table($tooltable, 'adminpresets_app_it_a');
1634 } else if (!$dbman->table_exists($table)) {
1635 // Adding fields to table adminpresets_app_it_a.
1636 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1637 $table->add_field('adminpresetapplyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1638 $table->add_field('configlogid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1639 $table->add_field('itemname', XMLDB_TYPE_CHAR, '100', null, null, null, null);
1641 // Adding keys to table adminpresets_app_it_a.
1642 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1644 // Adding indexes to table adminpresets_app_it_a.
1645 $table->add_index('configlogid', XMLDB_INDEX_NOTUNIQUE, ['configlogid']);
1646 $table->add_index('adminpresetapplyid', XMLDB_INDEX_NOTUNIQUE, ['adminpresetapplyid']);
1648 // Launch create table for adminpresets_app_it_a.
1649 $dbman->create_table($table);
1652 $tooltable = new xmldb_table('tool_admin_presets_plug');
1653 $table = new xmldb_table('adminpresets_plug');
1654 if ($dbman->table_exists($tooltable)) {
1655 $dbman->rename_table($tooltable, 'adminpresets_plug');
1656 } else if (!$dbman->table_exists($table)) {
1657 // Adding fields to table adminpresets_plug.
1658 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1659 $table->add_field('adminpresetid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1660 $table->add_field('plugin', XMLDB_TYPE_CHAR, '100', null, null, null, null);
1661 $table->add_field('name', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
1662 $table->add_field('enabled', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
1664 // Adding keys to table adminpresets_plug.
1665 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1667 // Adding indexes to table adminpresets_plug.
1668 $table->add_index('adminpresetid', XMLDB_INDEX_NOTUNIQUE, ['adminpresetid']);
1670 // Launch create table for adminpresets_plug.
1671 $dbman->create_table($table);
1674 $tooltable = new xmldb_table('tool_admin_presets_app_plug');
1675 $table = new xmldb_table('adminpresets_app_plug');
1676 if ($dbman->table_exists($tooltable)) {
1677 $dbman->rename_table($tooltable, 'adminpresets_app_plug');
1678 } else if (!$dbman->table_exists($table)) {
1679 // Adding fields to table adminpresets_app_plug.
1680 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1681 $table->add_field('adminpresetapplyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1682 $table->add_field('plugin', XMLDB_TYPE_CHAR, '100', null, null, null, null);
1683 $table->add_field('name', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
1684 $table->add_field('value', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
1685 $table->add_field('oldvalue', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
1687 // Adding keys to table adminpresets_app_plug.
1688 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
1690 // Adding indexes to table adminpresets_app_plug.
1691 $table->add_index('adminpresetapplyid', XMLDB_INDEX_NOTUNIQUE, ['adminpresetapplyid']);
1693 // Launch create table for adminpresets_app_plug.
1694 if (!$dbman->table_exists($table)) {
1695 $dbman->create_table($table);
1699 if ($DB->count_records('adminpresets', ['iscore' => 1]) == 0) {
1700 // Create default core site admin presets.
1701 require_once($CFG->dirroot . '/admin/presets/classes/helper.php');
1702 \core_adminpresets\helper::create_default_presets();
1705 // Main savepoint reached.
1706 upgrade_main_savepoint(true, 2021123000.01);
1709 if ($oldversion < 2021123000.02) {
1710 // If exists, migrate sensiblesettings admin settings from tool_admin_preset to adminpresets.
1711 if (get_config('tool_admin_presets', 'sensiblesettings') !== false) {
1712 set_config('sensiblesettings', get_config('tool_admin_presets', 'sensiblesettings'), 'adminpresets');
1713 unset_config('sensiblesettings', 'tool_admin_presets');
1716 // Main savepoint reached.
1717 upgrade_main_savepoint(true, 2021123000.02);
1720 if ($oldversion < 2021123000.03) {
1721 // If exists, migrate lastpresetapplied setting from tool_admin_preset to adminpresets.
1722 if (get_config('tool_admin_presets', 'lastpresetapplied') !== false) {
1723 set_config('lastpresetapplied', get_config('tool_admin_presets', 'lastpresetapplied'), 'adminpresets');
1724 unset_config('lastpresetapplied', 'tool_admin_presets');
1727 // Main savepoint reached.
1728 upgrade_main_savepoint(true, 2021123000.03);
1731 if ($oldversion < 2022011100.01) {
1732 // The following blocks have been hidden by default, so they shouldn't be enabled in the Full core preset: Course/site
1733 // summary, RSS feeds, Self completion and Feedback.
1734 $params = ['name' => get_string('fullpreset', 'core_adminpresets')];
1735 $fullpreset = $DB->get_record_select('adminpresets', 'name = :name and iscore > 0', $params);
1737 if (!$fullpreset) {
1738 // Full admin preset might have been created using the English name.
1739 $name = get_string_manager()->get_string('fullpreset', 'core_adminpresets', null, 'en');
1740 $params['name'] = $name;
1741 $fullpreset = $DB->get_record_select('adminpresets', 'name = :name and iscore > 0', $params);
1743 if (!$fullpreset) {
1744 // We tried, but we didn't find full by name. Let's find a core preset that sets 'usecomments' setting to 1.
1745 $sql = "SELECT preset.*
1746 FROM {adminpresets} preset
1747 INNER JOIN {adminpresets_it} it ON preset.id = it.adminpresetid
1748 WHERE it.name = :name AND it.value = :value AND preset.iscore > 0";
1749 $params = ['name' => 'usecomments', 'value' => '1'];
1750 $fullpreset = $DB->get_record_sql($sql, $params);
1753 if ($fullpreset) {
1754 $blocknames = ['course_summary', 'feedback', 'rss_client', 'selfcompletion'];
1755 list($blocksinsql, $blocksinparams) = $DB->get_in_or_equal($blocknames);
1757 // Remove entries from the adminpresets_app_plug table (in case the preset has been applied).
1758 $appliedpresets = $DB->get_records('adminpresets_app', ['adminpresetid' => $fullpreset->id], '', 'id');
1759 if ($appliedpresets) {
1760 list($appsinsql, $appsinparams) = $DB->get_in_or_equal(array_keys($appliedpresets));
1761 $sql = "adminpresetapplyid $appsinsql AND plugin='block' AND name $blocksinsql";
1762 $params = array_merge($appsinparams, $blocksinparams);
1763 $DB->delete_records_select('adminpresets_app_plug', $sql, $params);
1766 // Remove entries for these blocks from the adminpresets_plug table.
1767 $sql = "adminpresetid = ? AND plugin='block' AND name $blocksinsql";
1768 $params = array_merge([$fullpreset->id], $blocksinparams);
1769 $DB->delete_records_select('adminpresets_plug', $sql, $params);
1772 // Main savepoint reached.
1773 upgrade_main_savepoint(true, 2022011100.01);
1776 if ($oldversion < 2022012100.02) {
1777 // Migrate default message output config.
1778 $preferences = get_config('message');
1780 $treatedprefs = [];
1782 foreach ($preferences as $preference => $value) {
1783 // Extract provider and preference name from the setting name.
1784 // Example name: airnotifier_provider_enrol_imsenterprise_imsenterprise_enrolment_permitted
1785 // Provider: airnotifier
1786 // Preference: enrol_imsenterprise_imsenterprise_enrolment_permitted.
1787 $providerparts = explode('_provider_', $preference);
1788 if (count($providerparts) <= 1) {
1789 continue;
1792 $provider = $providerparts[0];
1793 $preference = $providerparts[1];
1795 // Extract and remove last part of the preference previously extracted: ie. permitted.
1796 $parts = explode('_', $preference);
1797 $key = array_pop($parts);
1799 if (in_array($key, ['permitted', 'loggedin', 'loggedoff'])) {
1800 if ($key == 'permitted') {
1801 // We will use provider name instead of permitted.
1802 $key = $provider;
1803 } else {
1804 // Logged in and logged off values are a csv of the enabled providers.
1805 $value = explode(',', $value);
1808 // Join the rest of the parts: ie enrol_imsenterprise_imsenterprise_enrolment.
1809 $prefname = implode('_', $parts);
1811 if (!isset($treatedprefs[$prefname])) {
1812 $treatedprefs[$prefname] = [];
1815 // Save the value with the selected key.
1816 $treatedprefs[$prefname][$key] = $value;
1820 // Now take every preference previous treated and its values.
1821 foreach ($treatedprefs as $prefname => $values) {
1822 $enabled = []; // List of providers enabled for each preference.
1824 // Enable if one of those is enabled.
1825 $loggedin = isset($values['loggedin']) ? $values['loggedin'] : [];
1826 foreach ($loggedin as $provider) {
1827 $enabled[$provider] = 1;
1829 $loggedoff = isset($values['loggedoff']) ? $values['loggedoff'] : [];
1830 foreach ($loggedoff as $provider) {
1831 $enabled[$provider] = 1;
1834 // Do not treat those values again.
1835 unset($values['loggedin']);
1836 unset($values['loggedoff']);
1838 // Translate rest of values coming from permitted "key".
1839 foreach ($values as $provider => $value) {
1840 $locked = false;
1842 switch ($value) {
1843 case 'forced':
1844 // Provider is enabled by force.
1845 $enabled[$provider] = 1;
1846 $locked = true;
1847 break;
1848 case 'disallowed':
1849 // Provider is disabled by force.
1850 unset($enabled[$provider]);
1851 $locked = true;
1852 break;
1853 default:
1854 // Provider is not forced (permitted) or invalid values.
1857 // Save locked.
1858 if ($locked) {
1859 set_config($provider.'_provider_'.$prefname.'_locked', 1, 'message');
1860 } else {
1861 set_config($provider.'_provider_'.$prefname.'_locked', 0, 'message');
1863 // Remove old value.
1864 unset_config($provider.'_provider_'.$prefname.'_permitted', 'message');
1867 // Save the new values.
1868 $value = implode(',', array_keys($enabled));
1869 set_config('message_provider_'.$prefname.'_enabled', $value, 'message');
1870 // Remove old values.
1871 unset_config('message_provider_'.$prefname.'_loggedin', 'message');
1872 unset_config('message_provider_'.$prefname.'_loggedoff', 'message');
1875 // Migrate user preferences. ie merging message_provider_moodle_instantmessage_loggedoff with
1876 // message_provider_moodle_instantmessage_loggedin to message_provider_moodle_instantmessage_enabled.
1878 $allrecordsloggedoff = $DB->sql_like('name', ':loggedoff');
1879 $total = $DB->count_records_select(
1880 'user_preferences',
1881 $allrecordsloggedoff,
1882 ['loggedoff' => 'message_provider_%_loggedoff']
1884 $i = 0;
1885 if ($total == 0) {
1886 $total = 1; // Avoid division by zero.
1889 // Show a progress bar.
1890 $pbar = new progress_bar('upgradeusernotificationpreferences', 500, true);
1891 $pbar->update($i, $total, "Upgrading user notifications preferences - $i/$total.");
1893 // We're migrating provider per provider to reduce memory usage.
1894 $providers = $DB->get_records('message_providers', null, 'name');
1895 foreach ($providers as $provider) {
1896 // 60 minutes to migrate each provider.
1897 upgrade_set_timeout(3600);
1898 $componentproviderbase = 'message_provider_'.$provider->component.'_'.$provider->name;
1900 $loggedinname = $componentproviderbase.'_loggedin';
1901 $loggedoffname = $componentproviderbase.'_loggedoff';
1903 // Change loggedin to enabled.
1904 $enabledname = $componentproviderbase.'_enabled';
1905 $DB->set_field('user_preferences', 'name', $enabledname, ['name' => $loggedinname]);
1907 $selectparams = [
1908 'enabled' => $enabledname,
1909 'loggedoff' => $loggedoffname,
1911 $sql = 'SELECT m1.id loggedoffid, m1.value as loggedoff, m2.value as enabled, m2.id as enabledid
1912 FROM
1913 (SELECT id, userid, value FROM {user_preferences} WHERE name = :loggedoff) m1
1914 LEFT JOIN
1915 (SELECT id, userid, value FROM {user_preferences} WHERE name = :enabled) m2
1916 ON m1.userid = m2.userid';
1918 while (($rs = $DB->get_recordset_sql($sql, $selectparams, 0, 1000)) && $rs->valid()) {
1919 // 10 minutes for every chunk.
1920 upgrade_set_timeout(600);
1922 $deleterecords = [];
1923 $changename = [];
1924 $changevalue = []; // Multidimensional array with possible values as key to reduce SQL queries.
1925 foreach ($rs as $record) {
1926 if (empty($record->enabledid)) {
1927 // Enabled does not exists, change the name.
1928 $changename[] = $record->loggedoffid;
1929 } else if ($record->enabledid != $record->loggedoff) {
1930 // Exist and values differ (checked on SQL), update the enabled record.
1932 if ($record->enabled != 'none' && !empty($record->enabled)) {
1933 $enabledvalues = explode(',', $record->enabled);
1934 } else {
1935 $enabledvalues = [];
1938 if ($record->loggedoff != 'none' && !empty($record->loggedoff)) {
1939 $loggedoffvalues = explode(',', $record->loggedoff);
1940 } else {
1941 $loggedoffvalues = [];
1944 $values = array_unique(array_merge($enabledvalues, $loggedoffvalues));
1945 sort($values);
1947 $newvalue = empty($values) ? 'none' : implode(',', $values);
1948 if (!isset($changevalue[$newvalue])) {
1949 $changevalue[$newvalue] = [];
1951 $changevalue[$newvalue][] = $record->enabledid;
1953 $deleterecords[] = $record->loggedoffid;
1954 } else {
1955 // They are the same, just delete loggedoff one.
1956 $deleterecords[] = $record->loggedoffid;
1958 $i++;
1960 $rs->close();
1962 // Commit the changes.
1963 if (!empty($changename)) {
1964 $changenameparams = [
1965 'name' => $loggedoffname,
1967 $changenameselect = 'name = :name AND id IN (' . implode(',', $changename) . ')';
1968 $DB->set_field_select('user_preferences', 'name', $enabledname, $changenameselect, $changenameparams);
1971 if (!empty($changevalue)) {
1972 $changevalueparams = [
1973 'name' => $enabledname,
1975 foreach ($changevalue as $value => $ids) {
1976 $changevalueselect = 'name = :name AND id IN (' . implode(',', $ids) . ')';
1977 $DB->set_field_select('user_preferences', 'value', $value, $changevalueselect, $changevalueparams);
1981 if (!empty($deleterecords)) {
1982 $deleteparams = [
1983 'name' => $loggedoffname,
1985 $deleteselect = 'name = :name AND id IN (' . implode(',', $deleterecords) . ')';
1986 $DB->delete_records_select('user_preferences', $deleteselect, $deleteparams);
1989 // Update progress.
1990 $pbar->update($i, $total, "Upgrading user notifications preferences - $i/$total.");
1992 $rs->close();
1994 // Delete the rest of loggedoff values (that are equal than enabled).
1995 $deleteparams = [
1996 'name' => $loggedoffname,
1998 $deleteselect = 'name = :name';
1999 $i += $DB->count_records_select('user_preferences', $deleteselect, $deleteparams);
2000 $DB->delete_records_select('user_preferences', $deleteselect, $deleteparams);
2002 // Update progress.
2003 $pbar->update($i, $total, "Upgrading user notifications preferences - $i/$total.");
2006 core_plugin_manager::reset_caches();
2008 // Delete the orphan records.
2009 $allrecordsparams = ['loggedin' => 'message_provider_%_loggedin', 'loggedoff' => 'message_provider_%_loggedoff'];
2010 $allrecordsloggedin = $DB->sql_like('name', ':loggedin');
2011 $allrecordsloggedinoffsql = "$allrecordsloggedin OR $allrecordsloggedoff";
2012 $DB->delete_records_select('user_preferences', $allrecordsloggedinoffsql, $allrecordsparams);
2014 // Update progress.
2015 $pbar->update($total, $total, "Upgrading user notifications preferences - $total/$total.");
2017 upgrade_main_savepoint(true, 2022012100.02);
2020 // Introduce question versioning to core.
2021 // First, create the new tables.
2022 if ($oldversion < 2022020200.01) {
2023 // Define table question_bank_entries to be created.
2024 $table = new xmldb_table('question_bank_entries');
2026 // Adding fields to table question_bank_entries.
2027 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2028 $table->add_field('questioncategoryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0);
2029 $table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null);
2030 $table->add_field('ownerid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2032 // Adding keys to table question_bank_entries.
2033 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2034 $table->add_key('questioncategoryid', XMLDB_KEY_FOREIGN, ['questioncategoryid'], 'question_categories', ['id']);
2035 $table->add_key('ownerid', XMLDB_KEY_FOREIGN, ['ownerid'], 'user', ['id']);
2037 // Conditionally launch create table for question_bank_entries.
2038 if (!$dbman->table_exists($table)) {
2039 $dbman->create_table($table);
2042 // Create category id and id number index.
2043 $index = new xmldb_index('categoryidnumber', XMLDB_INDEX_UNIQUE, ['questioncategoryid', 'idnumber']);
2045 // Conditionally launch add index categoryidnumber.
2046 if (!$dbman->index_exists($table, $index)) {
2047 $dbman->add_index($table, $index);
2050 // Define table question_versions to be created.
2051 $table = new xmldb_table('question_versions');
2053 // Adding fields to table question_versions.
2054 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2055 $table->add_field('questionbankentryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0);
2056 $table->add_field('version', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 1);
2057 $table->add_field('questionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0);
2058 $table->add_field('status', XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, 'ready');
2060 // Adding keys to table question_versions.
2061 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2062 $table->add_key('questionbankentryid', XMLDB_KEY_FOREIGN, ['questionbankentryid'], 'question_bank_entries', ['id']);
2063 $table->add_key('questionid', XMLDB_KEY_FOREIGN, ['questionid'], 'question', ['id']);
2065 // Conditionally launch create table for question_versions.
2066 if (!$dbman->table_exists($table)) {
2067 $dbman->create_table($table);
2070 // Define table question_references to be created.
2071 $table = new xmldb_table('question_references');
2073 // Adding fields to table question_references.
2074 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2075 $table->add_field('usingcontextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0);
2076 $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null);
2077 $table->add_field('questionarea', XMLDB_TYPE_CHAR, '50', null, null, null, null);
2078 $table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2079 $table->add_field('questionbankentryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0);
2080 $table->add_field('version', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2082 // Adding keys to table question_references.
2083 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2084 $table->add_key('usingcontextid', XMLDB_KEY_FOREIGN, ['usingcontextid'], 'context', ['id']);
2085 $table->add_key('questionbankentryid', XMLDB_KEY_FOREIGN, ['questionbankentryid'], 'question_bank_entries', ['id']);
2087 // Conditionally launch create table for question_references.
2088 if (!$dbman->table_exists($table)) {
2089 $dbman->create_table($table);
2092 // Define table question_set_references to be created.
2093 $table = new xmldb_table('question_set_references');
2095 // Adding fields to table question_set_references.
2096 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2097 $table->add_field('usingcontextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0);
2098 $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null);
2099 $table->add_field('questionarea', XMLDB_TYPE_CHAR, '50', null, null, null, null);
2100 $table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2101 $table->add_field('questionscontextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0);
2102 $table->add_field('filtercondition', XMLDB_TYPE_TEXT, null, null, null, null, null);
2104 // Adding keys to table question_set_references.
2105 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2106 $table->add_key('usingcontextid', XMLDB_KEY_FOREIGN, ['usingcontextid'], 'context', ['id']);
2107 $table->add_key('questionscontextid', XMLDB_KEY_FOREIGN, ['questionscontextid'], 'context', ['id']);
2109 // Conditionally launch create table for question_set_references.
2110 if (!$dbman->table_exists($table)) {
2111 $dbman->create_table($table);
2114 // Main savepoint reached.
2115 upgrade_main_savepoint(true, 2022020200.01);
2118 if ($oldversion < 2022020200.02) {
2119 // Define a new temporary field in the question_bank_entries tables.
2120 // Creating temporary field questionid to populate the data in question version table.
2121 // This will make sure the appropriate question id is inserted the version table without making any complex joins.
2122 $table = new xmldb_table('question_bank_entries');
2123 $field = new xmldb_field('questionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_TYPE_INTEGER);
2124 if (!$dbman->field_exists($table, $field)) {
2125 $dbman->add_field($table, $field);
2128 $transaction = $DB->start_delegated_transaction();
2129 upgrade_set_timeout(3600);
2130 // Create the data for the question_bank_entries table with, including the new temporary field.
2131 $sql = <<<EOF
2132 INSERT INTO {question_bank_entries}
2133 (questionid, questioncategoryid, idnumber, ownerid)
2134 SELECT id, category, idnumber, createdby
2135 FROM {question} q
2136 EOF;
2138 // Inserting question_bank_entries data.
2139 $DB->execute($sql);
2141 $transaction->allow_commit();
2143 // Main savepoint reached.
2144 upgrade_main_savepoint(true, 2022020200.02);
2147 if ($oldversion < 2022020200.03) {
2148 $transaction = $DB->start_delegated_transaction();
2149 upgrade_set_timeout(3600);
2150 // Create the question_versions using that temporary field.
2151 $sql = <<<EOF
2152 INSERT INTO {question_versions}
2153 (questionbankentryid, questionid, status)
2154 SELECT
2155 qbe.id,
2156 q.id,
2157 CASE
2158 WHEN q.hidden > 0 THEN 'hidden'
2159 ELSE 'ready'
2161 FROM {question_bank_entries} qbe
2162 INNER JOIN {question} q ON qbe.questionid = q.id
2163 EOF;
2165 // Inserting question_versions data.
2166 $DB->execute($sql);
2168 $transaction->allow_commit();
2170 // Dropping temporary field questionid.
2171 $table = new xmldb_table('question_bank_entries');
2172 $field = new xmldb_field('questionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_TYPE_INTEGER);
2173 if ($dbman->field_exists($table, $field)) {
2174 $dbman->drop_field($table, $field);
2177 // Main savepoint reached.
2178 upgrade_main_savepoint(true, 2022020200.03);
2181 if ($oldversion < 2022020200.04) {
2182 $transaction = $DB->start_delegated_transaction();
2183 upgrade_set_timeout(3600);
2184 // Create the base data for the random questions in the set_references table.
2185 // This covers most of the hard work in one go.
2186 $concat = $DB->sql_concat("'{\"questioncategoryid\":\"'", 'q.category', "'\",\"includingsubcategories\":\"'",
2187 'qs.includingsubcategories', "'\"}'");
2188 $sql = <<<EOF
2189 INSERT INTO {question_set_references}
2190 (usingcontextid, component, questionarea, itemid, questionscontextid, filtercondition)
2191 SELECT
2192 c.id,
2193 'mod_quiz',
2194 'slot',
2195 qs.id,
2196 qc.contextid,
2197 $concat
2198 FROM {question} q
2199 INNER JOIN {quiz_slots} qs on q.id = qs.questionid
2200 INNER JOIN {course_modules} cm ON cm.instance = qs.quizid AND cm.module = :quizmoduleid
2201 INNER JOIN {context} c ON cm.id = c.instanceid AND c.contextlevel = :contextmodule
2202 INNER JOIN {question_categories} qc ON qc.id = q.category
2203 WHERE q.qtype = :random
2204 EOF;
2206 // Inserting question_set_references data.
2207 $DB->execute($sql, [
2208 'quizmoduleid' => $DB->get_field('modules', 'id', ['name' => 'quiz']),
2209 'contextmodule' => CONTEXT_MODULE,
2210 'random' => 'random',
2213 $transaction->allow_commit();
2215 // Main savepoint reached.
2216 upgrade_main_savepoint(true, 2022020200.04);
2219 if ($oldversion < 2022020200.05) {
2220 $transaction = $DB->start_delegated_transaction();
2221 upgrade_set_timeout(3600);
2223 // Count all the slot tags to be migrated (for progress bar).
2224 $total = $DB->count_records('quiz_slot_tags');
2225 $pbar = new progress_bar('migratequestiontags', 1000, true);
2226 $i = 0;
2227 // Updating slot_tags for random question tags.
2228 // Now fetch any quiz slot tags and update those slot details into the question_set_references.
2229 $slottags = $DB->get_recordset('quiz_slot_tags', [], 'slotid ASC');
2231 $tagstrings = [];
2232 $lastslot = null;
2233 $runinsert = function (int $lastslot, array $tagstrings) use ($DB) {
2234 $conditiondata = $DB->get_field('question_set_references', 'filtercondition',
2235 ['itemid' => $lastslot, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
2237 // It is possible to have leftover tags in the database, without a corresponding
2238 // slot, because of an old bugs (e.g. MDL-76193). Therefore, if the slot is not found,
2239 // we can safely discard these tags.
2240 if (!empty($conditiondata)) {
2241 $condition = json_decode($conditiondata);
2242 $condition->tags = $tagstrings;
2243 $DB->set_field('question_set_references', 'filtercondition', json_encode($condition),
2244 ['itemid' => $lastslot, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
2248 foreach ($slottags as $tag) {
2249 upgrade_set_timeout(3600);
2250 if ($lastslot && $tag->slotid != $lastslot) {
2251 if (!empty($tagstrings)) {
2252 // Insert the data.
2253 $runinsert($lastslot, $tagstrings);
2255 // Prepare for the next slot id.
2256 $tagstrings = [];
2259 $lastslot = $tag->slotid;
2260 $tagstrings[] = "{$tag->tagid},{$tag->tagname}";
2261 // Update progress.
2262 $i++;
2263 $pbar->update($i, $total, "Migrating question tags - $i/$total.");
2265 if ($tagstrings) {
2266 $runinsert($lastslot, $tagstrings);
2268 $slottags->close();
2270 $transaction->allow_commit();
2271 // Main savepoint reached.
2272 upgrade_main_savepoint(true, 2022020200.05);
2275 if ($oldversion < 2022020200.06) {
2276 $transaction = $DB->start_delegated_transaction();
2277 upgrade_set_timeout(3600);
2278 // Create question_references record for each question.
2279 // Except if qtype is random. That case is handled by question_set_reference.
2280 $sql = "INSERT INTO {question_references}
2281 (usingcontextid, component, questionarea, itemid, questionbankentryid)
2282 SELECT c.id, 'mod_quiz', 'slot', qs.id, qv.questionbankentryid
2283 FROM {question} q
2284 JOIN {question_versions} qv ON q.id = qv.questionid
2285 JOIN {quiz_slots} qs ON q.id = qs.questionid
2286 JOIN {modules} m ON m.name = 'quiz'
2287 JOIN {course_modules} cm ON cm.module = m.id AND cm.instance = qs.quizid
2288 JOIN {context} c ON c.instanceid = cm.id AND c.contextlevel = " . CONTEXT_MODULE . "
2289 WHERE q.qtype <> 'random'";
2291 // Inserting question_references data.
2292 $DB->execute($sql);
2294 $transaction->allow_commit();
2295 // Main savepoint reached.
2296 upgrade_main_savepoint(true, 2022020200.06);
2299 // Finally, drop fields from question table.
2300 if ($oldversion < 2022020200.07) {
2301 // Define fields to be dropped from questions.
2302 $table = new xmldb_table('question');
2304 $field = new xmldb_field('version');
2305 // Conditionally launch drop field version.
2306 if ($dbman->field_exists($table, $field)) {
2307 $dbman->drop_field($table, $field);
2310 $field = new xmldb_field('hidden');
2311 // Conditionally launch drop field hidden.
2312 if ($dbman->field_exists($table, $field)) {
2313 $dbman->drop_field($table, $field);
2316 // Define index categoryidnumber (not unique) to be dropped form question.
2317 $index = new xmldb_index('categoryidnumber', XMLDB_INDEX_UNIQUE, ['category', 'idnumber']);
2319 // Conditionally launch drop index categoryidnumber.
2320 if ($dbman->index_exists($table, $index)) {
2321 $dbman->drop_index($table, $index);
2324 // Define key category (foreign) to be dropped form questions.
2325 $key = new xmldb_key('category', XMLDB_KEY_FOREIGN, ['category'], 'question_categories', ['id']);
2327 // Launch drop key category.
2328 $dbman->drop_key($table, $key);
2330 $field = new xmldb_field('idnumber');
2331 // Conditionally launch drop field idnumber.
2332 if ($dbman->field_exists($table, $field)) {
2333 $dbman->drop_field($table, $field);
2336 $field = new xmldb_field('category');
2337 // Conditionally launch drop field category.
2338 if ($dbman->field_exists($table, $field)) {
2339 $dbman->drop_field($table, $field);
2342 // Main savepoint reached.
2343 upgrade_main_savepoint(true, 2022020200.07);
2346 if ($oldversion < 2022021100.01) {
2347 $sql = "SELECT preset.*
2348 FROM {adminpresets} preset
2349 INNER JOIN {adminpresets_it} it ON preset.id = it.adminpresetid
2350 WHERE it.name = :name AND it.value = :value AND preset.iscore > 0";
2351 // Some settings and plugins have been added/removed to the Starter and Full preset. Add them to the core presets if
2352 // they haven't been included yet.
2353 $params = ['name' => get_string('starterpreset', 'core_adminpresets'), 'iscore' => 1];
2354 $starterpreset = $DB->get_record('adminpresets', $params);
2355 if (!$starterpreset) {
2356 // Starter admin preset might have been created using the English name.
2357 $name = get_string_manager()->get_string('starterpreset', 'core_adminpresets', null, 'en');
2358 $params['name'] = $name;
2359 $starterpreset = $DB->get_record('adminpresets', $params);
2361 if (!$starterpreset) {
2362 // We tried, but we didn't find starter by name. Let's find a core preset that sets 'usecomments' setting to 0.
2363 $params = ['name' => 'usecomments', 'value' => '0'];
2364 $starterpreset = $DB->get_record_sql($sql, $params);
2367 $params = ['name' => get_string('fullpreset', 'core_adminpresets')];
2368 $fullpreset = $DB->get_record_select('adminpresets', 'name = :name and iscore > 0', $params);
2369 if (!$fullpreset) {
2370 // Full admin preset might have been created using the English name.
2371 $name = get_string_manager()->get_string('fullpreset', 'core_adminpresets', null, 'en');
2372 $params['name'] = $name;
2373 $fullpreset = $DB->get_record_select('adminpresets', 'name = :name and iscore > 0', $params);
2375 if (!$fullpreset) {
2376 // We tried, but we didn't find full by name. Let's find a core preset that sets 'usecomments' setting to 1.
2377 $params = ['name' => 'usecomments', 'value' => '1'];
2378 $fullpreset = $DB->get_record_sql($sql, $params);
2381 $settings = [
2382 // Settings. Hide Guest login button for Starter preset (and back to show for Full).
2384 'presetid' => $starterpreset->id,
2385 'plugin' => 'none',
2386 'name' => 'guestloginbutton',
2387 'value' => '0',
2390 'presetid' => $fullpreset->id,
2391 'plugin' => 'none',
2392 'name' => 'guestloginbutton',
2393 'value' => '1',
2395 // Settings. Set Activity chooser tabs to "Starred, All, Recommended"(1) for Starter and back it to default(0) for Full.
2397 'presetid' => $starterpreset->id,
2398 'plugin' => 'none',
2399 'name' => 'activitychoosertabmode',
2400 'value' => '1',
2403 'presetid' => $fullpreset->id,
2404 'plugin' => 'none',
2405 'name' => 'activitychoosertabmode',
2406 'value' => '0',
2409 foreach ($settings as $notused => $setting) {
2410 $params = ['adminpresetid' => $setting['presetid'], 'plugin' => $setting['plugin'], 'name' => $setting['name']];
2411 if (!$DB->record_exists('adminpresets_it', $params)) {
2412 $record = new \stdClass();
2413 $record->adminpresetid = $setting['presetid'];
2414 $record->plugin = $setting['plugin'];
2415 $record->name = $setting['name'];
2416 $record->value = $setting['value'];
2417 $DB->insert_record('adminpresets_it', $record);
2421 $plugins = [
2422 // Plugins. Blocks. Disable/enable Online users, Recently accessed courses and Starred courses.
2424 'presetid' => $starterpreset->id,
2425 'plugin' => 'block',
2426 'name' => 'online_users',
2427 'enabled' => '0',
2430 'presetid' => $fullpreset->id,
2431 'plugin' => 'block',
2432 'name' => 'online_users',
2433 'enabled' => '1',
2436 'presetid' => $starterpreset->id,
2437 'plugin' => 'block',
2438 'name' => 'recentlyaccessedcourses',
2439 'enabled' => '0',
2442 'presetid' => $fullpreset->id,
2443 'plugin' => 'block',
2444 'name' => 'recentlyaccessedcourses',
2445 'enabled' => '1',
2448 'presetid' => $starterpreset->id,
2449 'plugin' => 'block',
2450 'name' => 'starredcourses',
2451 'enabled' => '0',
2454 'presetid' => $fullpreset->id,
2455 'plugin' => 'block',
2456 'name' => 'starredcourses',
2457 'enabled' => '1',
2459 // Plugins. Enrolments. Disable/enable Guest access.
2461 'presetid' => $starterpreset->id,
2462 'plugin' => 'enrol',
2463 'name' => 'guest',
2464 'enabled' => '0',
2467 'presetid' => $fullpreset->id,
2468 'plugin' => 'enrol',
2469 'name' => 'guest',
2470 'enabled' => '1',
2473 foreach ($plugins as $notused => $plugin) {
2474 $params = ['adminpresetid' => $plugin['presetid'], 'plugin' => $plugin['plugin'], 'name' => $plugin['name']];
2475 if (!$DB->record_exists('adminpresets_plug', $params)) {
2476 $record = new \stdClass();
2477 $record->adminpresetid = $plugin['presetid'];
2478 $record->plugin = $plugin['plugin'];
2479 $record->name = $plugin['name'];
2480 $record->enabled = $plugin['enabled'];
2481 $DB->insert_record('adminpresets_plug', $record);
2485 // Settings: Remove customusermenuitems setting from Starter and Full presets.
2486 $sql = "(adminpresetid = ? OR adminpresetid = ?) AND plugin = 'none' AND name = 'customusermenuitems'";
2487 $params = [$starterpreset->id, $fullpreset->id];
2488 $DB->delete_records_select('adminpresets_it', $sql, $params);
2490 // Plugins. Question types. Re-enable Description and Essay for Starter.
2491 $sql = "(adminpresetid = ? OR adminpresetid = ?) AND plugin = 'qtype' AND (name = 'description' OR name = 'essay')";
2492 $DB->delete_records_select('adminpresets_plug', $sql, $params);
2494 // Main savepoint reached.
2495 upgrade_main_savepoint(true, 2022021100.01);
2499 if ($oldversion < 2022021100.02) {
2500 $table = new xmldb_table('task_scheduled');
2502 // Changing precision of field minute on table task_scheduled to (200).
2503 $field = new xmldb_field('minute', XMLDB_TYPE_CHAR, '200', null, XMLDB_NOTNULL, null, null, 'blocking');
2504 $dbman->change_field_precision($table, $field);
2505 // Changing precision of field hour on table task_scheduled to (70).
2506 $field = new xmldb_field('hour', XMLDB_TYPE_CHAR, '70', null, XMLDB_NOTNULL, null, null, 'minute');
2507 $dbman->change_field_precision($table, $field);
2508 // Changing precision of field day on table task_scheduled to (90).
2509 $field = new xmldb_field('day', XMLDB_TYPE_CHAR, '90', null, XMLDB_NOTNULL, null, null, 'hour');
2510 $dbman->change_field_precision($table, $field);
2511 // Changing precision of field month on table task_scheduled to (30).
2512 $field = new xmldb_field('month', XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, 'day');
2513 $dbman->change_field_precision($table, $field);
2515 // Main savepoint reached.
2516 upgrade_main_savepoint(true, 2022021100.02);
2519 if ($oldversion < 2022022600.01) {
2520 // Get all processor and existing preferences.
2521 $processors = $DB->get_records('message_processors');
2522 $providers = $DB->get_records('message_providers', null, '', 'id, name, component');
2523 $existingpreferences = get_config('message');
2525 foreach ($processors as $processor) {
2526 foreach ($providers as $provider) {
2527 // Setting default preference name.
2528 $componentproviderbase = $provider->component . '_' . $provider->name;
2529 $preferencename = $processor->name.'_provider_'.$componentproviderbase.'_locked';
2530 // If we do not have this setting yet, set it to 0.
2531 if (!isset($existingpreferences->{$preferencename})) {
2532 set_config($preferencename, 0, 'message');
2537 upgrade_main_savepoint(true, 2022022600.01);
2540 if ($oldversion < 2022030100.00) {
2541 $sql = "SELECT preset.*
2542 FROM {adminpresets} preset
2543 INNER JOIN {adminpresets_it} it ON preset.id = it.adminpresetid
2544 WHERE it.name = :name AND it.value = :value AND preset.iscore > 0";
2546 $name = get_string('starterpreset', 'core_adminpresets');
2547 $params = ['name' => $name, 'iscore' => 1];
2548 $starterpreset = $DB->get_record('adminpresets', $params);
2549 if (!$starterpreset) {
2550 // Starter admin preset might have been created using the English name. Let's change it to current language.
2551 $englishname = get_string_manager()->get_string('starterpreset', 'core_adminpresets', null, 'en');
2552 $params['name'] = $englishname;
2553 $starterpreset = $DB->get_record('adminpresets', $params);
2555 if (!$starterpreset) {
2556 // We tried, but we didn't find starter by name. Let's find a core preset that sets 'usecomments' setting to 0.
2557 $params = ['name' => 'usecomments', 'value' => '0'];
2558 $starterpreset = $DB->get_record_sql($sql, $params);
2560 // The iscore field is already 1 for starterpreset, so we don't need to change it.
2561 // We only need to update the name and comment in case they are different to current language strings.
2562 if ($starterpreset && $starterpreset->name != $name) {
2563 $starterpreset->name = $name;
2564 $starterpreset->comments = get_string('starterpresetdescription', 'core_adminpresets');
2565 $DB->update_record('adminpresets', $starterpreset);
2568 // Let's mark Full admin presets with current FULL_PRESETS value and change the name to current language.
2569 $name = get_string('fullpreset', 'core_adminpresets');
2570 $params = ['name' => $name];
2571 $fullpreset = $DB->get_record_select('adminpresets', 'name = :name and iscore > 0', $params);
2572 if (!$fullpreset) {
2573 // Full admin preset might have been created using the English name.
2574 $englishname = get_string_manager()->get_string('fullpreset', 'core_adminpresets', null, 'en');
2575 $params['name'] = $englishname;
2576 $fullpreset = $DB->get_record_select('adminpresets', 'name = :name and iscore > 0', $params);
2578 if (!$fullpreset) {
2579 // We tried, but we didn't find full by name. Let's find a core preset that sets 'usecomments' setting to 1.
2580 $params = ['name' => 'usecomments', 'value' => '1'];
2581 $fullpreset = $DB->get_record_sql($sql, $params);
2583 if ($fullpreset) {
2584 // We need to update iscore field value, whether the name is the same or not.
2585 $fullpreset->name = $name;
2586 $fullpreset->comments = get_string('fullpresetdescription', 'core_adminpresets');
2587 $fullpreset->iscore = 2;
2588 $DB->update_record('adminpresets', $fullpreset);
2590 // We are applying again changes made on 2022011100.01 upgrading step because of MDL-73953 bug.
2591 $blocknames = ['course_summary', 'feedback', 'rss_client', 'selfcompletion'];
2592 list($blocksinsql, $blocksinparams) = $DB->get_in_or_equal($blocknames);
2594 // Remove entries from the adminpresets_app_plug table (in case the preset has been applied).
2595 $appliedpresets = $DB->get_records('adminpresets_app', ['adminpresetid' => $fullpreset->id], '', 'id');
2596 if ($appliedpresets) {
2597 list($appsinsql, $appsinparams) = $DB->get_in_or_equal(array_keys($appliedpresets));
2598 $sql = "adminpresetapplyid $appsinsql AND plugin='block' AND name $blocksinsql";
2599 $params = array_merge($appsinparams, $blocksinparams);
2600 $DB->delete_records_select('adminpresets_app_plug', $sql, $params);
2603 // Remove entries for these blocks from the adminpresets_plug table.
2604 $sql = "adminpresetid = ? AND plugin='block' AND name $blocksinsql";
2605 $params = array_merge([$fullpreset->id], $blocksinparams);
2606 $DB->delete_records_select('adminpresets_plug', $sql, $params);
2609 // Main savepoint reached.
2610 upgrade_main_savepoint(true, 2022030100.00);
2613 if ($oldversion < 2022031100.01) {
2614 $reportsusermenuitem = 'reports,core_reportbuilder|/reportbuilder/index.php';
2615 upgrade_add_item_to_usermenu($reportsusermenuitem);
2616 // Main savepoint reached.
2617 upgrade_main_savepoint(true, 2022031100.01);
2620 if ($oldversion < 2022032200.01) {
2622 // Define index to be added to question_references.
2623 $table = new xmldb_table('question_references');
2624 $index = new xmldb_index('context-component-area-itemid', XMLDB_INDEX_UNIQUE,
2625 ['usingcontextid', 'component', 'questionarea', 'itemid']);
2627 // Conditionally launch add field id.
2628 if (!$dbman->index_exists($table, $index)) {
2629 $dbman->add_index($table, $index);
2632 // Main savepoint reached.
2633 upgrade_main_savepoint(true, 2022032200.01);
2636 if ($oldversion < 2022032200.02) {
2638 // Define index to be added to question_references.
2639 $table = new xmldb_table('question_set_references');
2640 $index = new xmldb_index('context-component-area-itemid', XMLDB_INDEX_UNIQUE,
2641 ['usingcontextid', 'component', 'questionarea', 'itemid']);
2643 // Conditionally launch add field id.
2644 if (!$dbman->index_exists($table, $index)) {
2645 $dbman->add_index($table, $index);
2648 // Main savepoint reached.
2649 upgrade_main_savepoint(true, 2022032200.02);
2652 if ($oldversion < 2022041200.01) {
2654 // The original default admin presets "sensible settings" (those that should be treated as sensitive).
2655 $originalsensiblesettings = 'recaptchapublickey@@none, recaptchaprivatekey@@none, googlemapkey3@@none, ' .
2656 'secretphrase@@url, cronremotepassword@@none, smtpuser@@none, smtppass@none, proxypassword@@none, ' .
2657 'quizpassword@@quiz, allowedip@@none, blockedip@@none, dbpass@@logstore_database, messageinbound_hostpass@@none, ' .
2658 'bind_pw@@auth_cas, pass@@auth_db, bind_pw@@auth_ldap, dbpass@@enrol_database, bind_pw@@enrol_ldap, ' .
2659 'server_password@@search_solr, ssl_keypassword@@search_solr, alternateserver_password@@search_solr, ' .
2660 'alternatessl_keypassword@@search_solr, test_password@@cachestore_redis, password@@mlbackend_python';
2662 // Check if the current config matches the original default, upgrade to new default if so.
2663 if (get_config('adminpresets', 'sensiblesettings') === $originalsensiblesettings) {
2664 $newsensiblesettings = "{$originalsensiblesettings}, badges_badgesalt@@none, calendar_exportsalt@@none";
2665 set_config('sensiblesettings', $newsensiblesettings, 'adminpresets');
2668 // Main savepoint reached.
2669 upgrade_main_savepoint(true, 2022041200.01);
2672 // Automatically generated Moodle v4.0.0 release upgrade line.
2673 // Put any upgrade step following this.
2675 if ($oldversion < 2022042900.01) {
2676 // Social custom fields could had been created linked to category id = 1. Let's check category 1 exists.
2677 if (!$DB->get_record('user_info_category', ['id' => 1])) {
2678 // Let's check if we have any custom field linked to category id = 1.
2679 $fields = $DB->get_records('user_info_field', ['categoryid' => 1]);
2680 if (!empty($fields)) {
2681 $categoryid = $DB->get_field_sql('SELECT min(id) from {user_info_category}');
2682 foreach ($fields as $field) {
2683 $field->categoryid = $categoryid;
2684 $DB->update_record('user_info_field', $field);
2689 // Main savepoint reached.
2690 upgrade_main_savepoint(true, 2022042900.01);
2693 if ($oldversion < 2022051000.00) {
2694 // Add index to the sid field in the external_tokens table.
2695 $table = new xmldb_table('external_tokens');
2696 $index = new xmldb_index('sid', XMLDB_INDEX_NOTUNIQUE, ['sid']);
2698 if (!$dbman->index_exists($table, $index)) {
2699 $dbman->add_index($table, $index);
2702 upgrade_main_savepoint(true, 2022051000.00);
2705 if ($oldversion < 2022052500.00) {
2706 // Start an adhoc task to fix the file timestamps of restored files.
2707 $task = new core\task\fix_file_timestamps_task();
2708 \core\task\manager::queue_adhoc_task($task);
2710 // Main savepoint reached.
2711 upgrade_main_savepoint(true, 2022052500.00);
2714 if ($oldversion < 2022052700.01) {
2716 // Define index timestarted_idx (not unique) to be added to task_adhoc.
2717 $table = new xmldb_table('task_adhoc');
2718 $index = new xmldb_index('timestarted_idx', XMLDB_INDEX_NOTUNIQUE, ['timestarted']);
2720 // Conditionally launch add index timestarted_idx.
2721 if (!$dbman->index_exists($table, $index)) {
2722 $dbman->add_index($table, $index);
2725 // Main savepoint reached.
2726 upgrade_main_savepoint(true, 2022052700.01);
2729 if ($oldversion < 2022052700.02) {
2731 // Define index filename (not unique) to be added to files.
2732 $table = new xmldb_table('files');
2733 $index = new xmldb_index('filename', XMLDB_INDEX_NOTUNIQUE, ['filename']);
2735 // Conditionally launch add index filename.
2736 if (!$dbman->index_exists($table, $index)) {
2737 $dbman->add_index($table, $index);
2740 // Main savepoint reached.
2741 upgrade_main_savepoint(true, 2022052700.02);
2744 if ($oldversion < 2022060300.01) {
2746 // Changing precision of field hidden on table grade_categories to (10).
2747 $table = new xmldb_table('grade_categories');
2748 $field = new xmldb_field('hidden', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'timemodified');
2750 // Launch change of precision for field hidden.
2751 $dbman->change_field_precision($table, $field);
2753 // Changing precision of field hidden on table grade_categories_history to (10).
2754 $table = new xmldb_table('grade_categories_history');
2755 $field = new xmldb_field('hidden', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'aggregatesubcats');
2757 // Launch change of precision for field hidden.
2758 $dbman->change_field_precision($table, $field);
2760 // Main savepoint reached.
2761 upgrade_main_savepoint(true, 2022060300.01);
2764 if ($oldversion < 2022061000.01) {
2765 // Iterate over custom user menu items configuration, removing pix icon references.
2766 $customusermenuitems = str_replace(["\r\n", "\r"], "\n", $CFG->customusermenuitems);
2768 $lines = preg_split('/\n/', $customusermenuitems, -1, PREG_SPLIT_NO_EMPTY);
2769 $lines = array_map(static function(string $line): string {
2770 // Previous format was "<langstring>|<url>[|<pixicon>]" - pix icon is no longer supported.
2771 $lineparts = explode('|', trim($line), 3);
2772 // Return first two parts of line.
2773 return implode('|', array_slice($lineparts, 0, 2));
2774 }, $lines);
2776 set_config('customusermenuitems', implode("\n", $lines));
2778 upgrade_main_savepoint(true, 2022061000.01);
2781 if ($oldversion < 2022061500.00) {
2782 // Remove drawer-open-nav user preference for every user.
2783 $DB->delete_records('user_preferences', ['name' => 'drawer-open-nav']);
2785 // Main savepoint reached.
2786 upgrade_main_savepoint(true, 2022061500.00);
2790 if ($oldversion < 2022072900.00) {
2791 // Call the helper function that updates the foreign keys and indexes in MDL-49795.
2792 upgrade_add_foreign_key_and_indexes();
2794 // Main savepoint reached.
2795 upgrade_main_savepoint(true, 2022072900.00);
2798 if ($oldversion < 2022081200.01) {
2800 // Define field lang to be added to course_modules.
2801 $table = new xmldb_table('course_modules');
2802 $field = new xmldb_field('lang', XMLDB_TYPE_CHAR, '30', null, null, null, null, 'downloadcontent');
2804 // Conditionally launch add field lang.
2805 if (!$dbman->field_exists($table, $field)) {
2806 $dbman->add_field($table, $field);
2809 // Main savepoint reached.
2810 upgrade_main_savepoint(true, 2022081200.01);
2813 if ($oldversion < 2022091000.01) {
2814 $table = new xmldb_table('h5p');
2815 $indexpathnamehash = new xmldb_index('pathnamehash_idx', XMLDB_INDEX_NOTUNIQUE, ['pathnamehash']);
2817 if (!$dbman->index_exists($table, $indexpathnamehash)) {
2818 $dbman->add_index($table, $indexpathnamehash);
2820 // Main savepoint reached.
2821 upgrade_main_savepoint(true, 2022091000.01);
2824 if ($oldversion < 2022092200.01) {
2826 // Remove any orphaned tag instance records (pointing to non-existing context).
2827 $DB->delete_records_select('tag_instance', 'NOT EXISTS (
2828 SELECT ctx.id FROM {context} ctx WHERE ctx.id = {tag_instance}.contextid
2829 )');
2831 // Main savepoint reached.
2832 upgrade_main_savepoint(true, 2022092200.01);
2835 if ($oldversion < 2022101400.01) {
2836 $table = new xmldb_table('competency_modulecomp');
2837 $field = new xmldb_field('overridegrade', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'ruleoutcome');
2839 if (!$dbman->field_exists($table, $field)) {
2840 $dbman->add_field($table, $field);
2843 // Main savepoint reached.
2844 upgrade_main_savepoint(true, 2022101400.01);
2847 if ($oldversion < 2022101400.03) {
2848 // Define table to store completion viewed.
2849 $table = new xmldb_table('course_modules_viewed');
2851 // Adding fields to table course_modules_viewed.
2852 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2853 $table->add_field('coursemoduleid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
2854 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'coursemoduleid');
2855 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid');
2857 // Adding keys to table course_modules_viewed.
2858 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2860 // Adding indexes to table course_modules_viewed.
2861 $table->add_index('coursemoduleid', XMLDB_INDEX_NOTUNIQUE, ['coursemoduleid']);
2862 $table->add_index('userid-coursemoduleid', XMLDB_INDEX_UNIQUE, ['userid', 'coursemoduleid']);
2864 if (!$dbman->table_exists($table)) {
2865 $dbman->create_table($table);
2868 // Main savepoint reached.
2869 upgrade_main_savepoint(true, 2022101400.03);
2872 if ($oldversion < 2022101400.04) {
2873 // Add legacy data to the new table.
2874 $transaction = $DB->start_delegated_transaction();
2875 upgrade_set_timeout(3600);
2876 $sql = "INSERT INTO {course_modules_viewed}
2877 (userid, coursemoduleid, timecreated)
2878 SELECT userid, coursemoduleid, timemodified
2879 FROM {course_modules_completion}
2880 WHERE viewed = 1";
2881 $DB->execute($sql);
2882 $transaction->allow_commit();
2884 // Main savepoint reached.
2885 upgrade_main_savepoint(true, 2022101400.04);
2888 if ($oldversion < 2022101400.05) {
2889 // Define field viewed to be dropped from course_modules_completion.
2890 $table = new xmldb_table('course_modules_completion');
2891 $field = new xmldb_field('viewed');
2893 // Conditionally launch drop field viewed.
2894 if ($dbman->field_exists($table, $field)) {
2895 $dbman->drop_field($table, $field);
2898 // Main savepoint reached.
2899 upgrade_main_savepoint(true, 2022101400.05);
2902 if ($oldversion < 2022102800.01) {
2903 // For sites with "contact site support" already available (4.0.x), maintain existing functionality.
2904 if ($oldversion >= 2022041900.00) {
2905 set_config('supportavailability', CONTACT_SUPPORT_ANYONE);
2906 } else {
2907 // Sites which did not previously have the "contact site support" feature default to it requiring authentication.
2908 set_config('supportavailability', CONTACT_SUPPORT_AUTHENTICATED);
2911 // Main savepoint reached.
2912 upgrade_main_savepoint(true, 2022102800.01);
2915 if ($oldversion < 2022110600.00) {
2916 // If webservice_xmlrpc isn't any longer installed, remove its configuration,
2917 // capabilities and presence in other settings.
2918 if (!file_exists($CFG->dirroot . '/webservice/xmlrpc/version.php')) {
2919 // No DB structures to delete in this plugin.
2921 // Remove capabilities.
2922 capabilities_cleanup('webservice_xmlrpc');
2924 // Remove own configuration.
2925 unset_all_config_for_plugin('webservice_xmlrpc');
2927 // Remove it from the enabled protocols if it was there.
2928 $protos = get_config('core', 'webserviceprotocols');
2929 $protoarr = explode(',', $protos);
2930 $protoarr = array_filter($protoarr, function($ele) {
2931 return trim($ele) !== 'xmlrpc';
2933 $protos = implode(',', $protoarr);
2934 set_config('webserviceprotocols', $protos);
2937 // Main savepoint reached.
2938 upgrade_main_savepoint(true, 2022110600.00);
2941 // Automatically generated Moodle v4.1.0 release upgrade line.
2942 // Put any upgrade step following this.
2944 if ($oldversion < 2022120900.01) {
2946 // Remove any orphaned role assignment records (pointing to non-existing roles).
2947 $DB->delete_records_select('role_assignments', 'NOT EXISTS (
2948 SELECT r.id FROM {role} r WHERE r.id = {role_assignments}.roleid
2949 )');
2951 // Main savepoint reached.
2952 upgrade_main_savepoint(true, 2022120900.01);
2955 if ($oldversion < 2022121600.01) {
2956 // Define index blocknameindex (not unique) to be added to block_instances.
2957 $table = new xmldb_table('block_instances');
2958 $index = new xmldb_index('blocknameindex', XMLDB_INDEX_NOTUNIQUE, ['blockname']);
2960 // Conditionally launch add index blocknameindex.
2961 if (!$dbman->index_exists($table, $index)) {
2962 $dbman->add_index($table, $index);
2964 // Main savepoint reached.
2965 upgrade_main_savepoint(true, 2022121600.01);
2968 if ($oldversion < 2023010300.00) {
2969 // The useexternalyui setting has been removed.
2970 unset_config('useexternalyui');
2972 // Main savepoint reached.
2973 upgrade_main_savepoint(true, 2023010300.00);
2976 if ($oldversion < 2023020800.00) {
2977 // If cachestore_memcached is no longer present, remove it.
2978 if (!file_exists($CFG->dirroot . '/cache/stores/memcached/version.php')) {
2979 // Clean config.
2980 unset_all_config_for_plugin('cachestore_memcached');
2983 // Main savepoint reached.
2984 upgrade_main_savepoint(true, 2023020800.00);
2987 return true;