See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
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. 13 // 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/>. 16 17 /** 18 * This file keeps track of upgrades to Moodle. 19 * 20 * Sometimes, changes between versions involve 21 * alterations to database structures and other 22 * major things that may break installations. 23 * 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. 27 * 28 * If there's something it cannot do itself, it 29 * will tell you what you need to do. 30 * 31 * The commands in here will all be database-neutral, 32 * using the methods of database_manager class 33 * 34 * Please do not forget to use upgrade_set_timeout() 35 * before any action that may take longer time to finish. 36 * 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 41 */ 42 43 defined('MOODLE_INTERNAL') || die(); 44 45 /** 46 * Main upgrade tasks to be executed on Moodle version bump 47 * 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. 51 * 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. 56 * 57 * Each upgrade step has a fixed structure, that can be summarised as follows: 58 * 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 * } 66 * 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 * - .... 74 * 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. 79 * 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} 83 * 84 * @param int $oldversion 85 * @return bool always true 86 */ 87 function xmldb_main_upgrade($oldversion) { 88 global $CFG, $DB; 89 90 require_once($CFG->libdir.'/db/upgradelib.php'); // Core Upgrade-related functions. 91 92 $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes. 93 94 // Always keep this upgrade step with version being the minimum 95 // allowed version to upgrade from (v3.5.0 right now). 96 if ($oldversion < 2018051700) { 97 // Just in case somebody hacks upgrade scripts or env, we really can not continue. 98 echo("You need to upgrade to 3.5.x 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, 2018051700); 102 } 103 104 // Automatically generated Moodle v3.5.0 release upgrade line. 105 // Put any upgrade step following this. 106 107 if ($oldversion < 2018062800.01) { 108 // Add foreign key fk_user to the comments table. 109 $table = new xmldb_table('comments'); 110 $key = new xmldb_key('fk_user', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id')); 111 $dbman->add_key($table, $key); 112 113 upgrade_main_savepoint(true, 2018062800.01); 114 } 115 116 if ($oldversion < 2018062800.02) { 117 // Add composite index ix_concomitem to the table comments. 118 $table = new xmldb_table('comments'); 119 $index = new xmldb_index('ix_concomitem', XMLDB_INDEX_NOTUNIQUE, array('contextid', 'commentarea', 'itemid')); 120 121 if (!$dbman->index_exists($table, $index)) { 122 $dbman->add_index($table, $index); 123 } 124 125 upgrade_main_savepoint(true, 2018062800.02); 126 } 127 128 if ($oldversion < 2018062800.03) { 129 // Define field location to be added to event. 130 $table = new xmldb_table('event'); 131 $field = new xmldb_field('location', XMLDB_TYPE_TEXT, null, null, null, null, null, 'priority'); 132 133 // Conditionally launch add field location. 134 if (!$dbman->field_exists($table, $field)) { 135 $dbman->add_field($table, $field); 136 } 137 138 // Main savepoint reached. 139 upgrade_main_savepoint(true, 2018062800.03); 140 } 141 142 if ($oldversion < 2018072500.00) { 143 // Find all duplicate top level categories per context. 144 $duplicates = $DB->get_records_sql("SELECT qc1.* 145 FROM {question_categories} qc1 146 JOIN {question_categories} qc2 147 ON qc1.contextid = qc2.contextid AND qc1.id <> qc2.id 148 WHERE qc1.parent = 0 AND qc2.parent = 0 149 ORDER BY qc1.contextid, qc1.id"); 150 151 // For each context, let the first top category to remain as top category and make the rest its children. 152 $currentcontextid = 0; 153 $chosentopid = 0; 154 foreach ($duplicates as $duplicate) { 155 if ($currentcontextid != $duplicate->contextid) { 156 $currentcontextid = $duplicate->contextid; 157 $chosentopid = $duplicate->id; 158 } else { 159 $DB->set_field('question_categories', 'parent', $chosentopid, ['id' => $duplicate->id]); 160 } 161 } 162 163 // Main savepoint reached. 164 upgrade_main_savepoint(true, 2018072500.00); 165 } 166 167 if ($oldversion < 2018073000.00) { 168 // Main savepoint reached. 169 if (!file_exists($CFG->dirroot . '/admin/tool/assignmentupgrade/version.php')) { 170 unset_all_config_for_plugin('tool_assignmentupgrade'); 171 } 172 upgrade_main_savepoint(true, 2018073000.00); 173 } 174 175 if ($oldversion < 2018083100.01) { 176 // Remove module associated blog posts for non-existent (deleted) modules. 177 $sql = "SELECT ba.contextid as modcontextid 178 FROM {blog_association} ba 179 JOIN {post} p 180 ON p.id = ba.blogid 181 LEFT JOIN {context} c 182 ON c.id = ba.contextid 183 WHERE p.module = :module 184 AND c.contextlevel IS NULL 185 GROUP BY ba.contextid"; 186 if ($deletedmodules = $DB->get_records_sql($sql, array('module' => 'blog'))) { 187 foreach ($deletedmodules as $module) { 188 $assocblogids = $DB->get_fieldset_select('blog_association', 'blogid', 189 'contextid = :contextid', ['contextid' => $module->modcontextid]); 190 list($sql, $params) = $DB->get_in_or_equal($assocblogids, SQL_PARAMS_NAMED); 191 192 $DB->delete_records_select('tag_instance', "itemid $sql", $params); 193 $DB->delete_records_select('post', "id $sql AND module = :module", 194 array_merge($params, ['module' => 'blog'])); 195 $DB->delete_records('blog_association', ['contextid' => $module->modcontextid]); 196 } 197 } 198 199 // Main savepoint reached. 200 upgrade_main_savepoint(true, 2018083100.01); 201 } 202 203 if ($oldversion < 2018091200.00) { 204 if (!file_exists($CFG->dirroot . '/cache/stores/memcache/settings.php')) { 205 unset_all_config_for_plugin('cachestore_memcache'); 206 } 207 208 upgrade_main_savepoint(true, 2018091200.00); 209 } 210 211 if ($oldversion < 2018091700.01) { 212 // Remove unused setting. 213 unset_config('messaginghidereadnotifications'); 214 215 // Main savepoint reached. 216 upgrade_main_savepoint(true, 2018091700.01); 217 } 218 219 // Add idnumber fields to question and question_category tables. 220 // This is done in four parts to aid error recovery during upgrade, should that occur. 221 if ($oldversion < 2018092100.01) { 222 $table = new xmldb_table('question'); 223 $field = new xmldb_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'modifiedby'); 224 if (!$dbman->field_exists($table, $field)) { 225 $dbman->add_field($table, $field); 226 } 227 upgrade_main_savepoint(true, 2018092100.01); 228 } 229 230 if ($oldversion < 2018092100.02) { 231 $table = new xmldb_table('question'); 232 $index = new xmldb_index('categoryidnumber', XMLDB_INDEX_UNIQUE, array('category', 'idnumber')); 233 if (!$dbman->index_exists($table, $index)) { 234 $dbman->add_index($table, $index); 235 } 236 upgrade_main_savepoint(true, 2018092100.02); 237 } 238 239 if ($oldversion < 2018092100.03) { 240 $table = new xmldb_table('question_categories'); 241 $field = new xmldb_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'sortorder'); 242 if (!$dbman->field_exists($table, $field)) { 243 $dbman->add_field($table, $field); 244 } 245 upgrade_main_savepoint(true, 2018092100.03); 246 } 247 248 if ($oldversion < 2018092100.04) { 249 $table = new xmldb_table('question_categories'); 250 $index = new xmldb_index('contextididnumber', XMLDB_INDEX_UNIQUE, array('contextid', 'idnumber')); 251 if (!$dbman->index_exists($table, $index)) { 252 $dbman->add_index($table, $index); 253 } 254 // Main savepoint reached. 255 upgrade_main_savepoint(true, 2018092100.04); 256 } 257 258 if ($oldversion < 2018092800.00) { 259 // Alter the table 'message_contacts'. 260 $table = new xmldb_table('message_contacts'); 261 262 // Remove index so we can alter the fields. 263 $index = new xmldb_index('userid-contactid', XMLDB_INDEX_UNIQUE, ['userid', 'contactid']); 264 if ($dbman->index_exists($table, $index)) { 265 $dbman->drop_index($table, $index); 266 } 267 268 // Remove defaults of '0' from the 'userid' and 'contactid' fields. 269 $field = new xmldb_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id'); 270 $dbman->change_field_default($table, $field); 271 272 $field = new xmldb_field('contactid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid'); 273 $dbman->change_field_default($table, $field); 274 275 // Add the missing FKs that will now be added to new installs. 276 $key = new xmldb_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']); 277 $dbman->add_key($table, $key); 278 279 $key = new xmldb_key('contactid', XMLDB_KEY_FOREIGN, ['contactid'], 'user', ['id']); 280 $dbman->add_key($table, $key); 281 282 // Re-add the index. 283 if (!$dbman->index_exists($table, $index)) { 284 $dbman->add_index($table, $index); 285 } 286 287 // Add the field 'timecreated'. Allow null, since existing records won't have an accurate value we can use. 288 $field = new xmldb_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'blocked'); 289 if (!$dbman->field_exists($table, $field)) { 290 $dbman->add_field($table, $field); 291 } 292 293 // Create new 'message_contact_requests' table. 294 $table = new xmldb_table('message_contact_requests'); 295 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null); 296 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id'); 297 $table->add_field('requesteduserid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid'); 298 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'requesteduserid'); 299 300 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id'], null, null); 301 $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']); 302 $table->add_key('requesteduserid', XMLDB_KEY_FOREIGN, ['requesteduserid'], 'user', ['id']); 303 304 $table->add_index('userid-requesteduserid', XMLDB_INDEX_UNIQUE, ['userid', 'requesteduserid']); 305 306 if (!$dbman->table_exists($table)) { 307 $dbman->create_table($table); 308 } 309 310 // Create new 'message_users_blocked' table. 311 $table = new xmldb_table('message_users_blocked'); 312 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null); 313 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id'); 314 $table->add_field('blockeduserid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid'); 315 // Allow NULLs in the 'timecreated' field because we will be moving existing data here that has no timestamp. 316 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'blockeduserid'); 317 318 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id'], null, null); 319 $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']); 320 $table->add_key('blockeduserid', XMLDB_KEY_FOREIGN, ['blockeduserid'], 'user', ['id']); 321 322 $table->add_index('userid-blockeduserid', XMLDB_INDEX_UNIQUE, ['userid', 'blockeduserid']); 323 324 if (!$dbman->table_exists($table)) { 325 $dbman->create_table($table); 326 } 327 328 upgrade_main_savepoint(true, 2018092800.00); 329 } 330 331 if ($oldversion < 2018092800.01) { 332 // Move all the 'blocked' contacts to the new table 'message_users_blocked'. 333 $updatesql = "INSERT INTO {message_users_blocked} (userid, blockeduserid, timecreated) 334 SELECT userid, contactid, null as timecreated 335 FROM {message_contacts} 336 WHERE blocked = :blocked"; 337 $DB->execute($updatesql, ['blocked' => 1]); 338 339 // Removed the 'blocked' column from 'message_contacts'. 340 $table = new xmldb_table('message_contacts'); 341 $field = new xmldb_field('blocked'); 342 $dbman->drop_field($table, $field); 343 344 upgrade_main_savepoint(true, 2018092800.01); 345 } 346 347 if ($oldversion < 2018092800.02) { 348 // Delete any contacts that are not mutual (meaning they both haven't added each other). 349 do { 350 $sql = "SELECT c1.id 351 FROM {message_contacts} c1 352 LEFT JOIN {message_contacts} c2 353 ON c1.userid = c2.contactid 354 AND c1.contactid = c2.userid 355 WHERE c2.id IS NULL"; 356 if ($contacts = $DB->get_records_sql($sql, null, 0, 1000)) { 357 list($insql, $inparams) = $DB->get_in_or_equal(array_keys($contacts)); 358 $DB->delete_records_select('message_contacts', "id $insql", $inparams); 359 } 360 } while ($contacts); 361 362 upgrade_main_savepoint(true, 2018092800.02); 363 } 364 365 if ($oldversion < 2018092800.03) { 366 // Remove any duplicate rows - from now on adding contacts just requires 1 row. 367 // The person who made the contact request (userid) and the person who approved 368 // it (contactid). Upgrade the table so that the first person to add the contact 369 // was the one who made the request. 370 $sql = "SELECT c1.id 371 FROM {message_contacts} c1 372 INNER JOIN {message_contacts} c2 373 ON c1.userid = c2.contactid 374 AND c1.contactid = c2.userid 375 WHERE c1.id > c2.id"; 376 if ($contacts = $DB->get_records_sql($sql)) { 377 list($insql, $inparams) = $DB->get_in_or_equal(array_keys($contacts)); 378 $DB->delete_records_select('message_contacts', "id $insql", $inparams); 379 } 380 381 upgrade_main_savepoint(true, 2018092800.03); 382 } 383 384 if ($oldversion < 2018101700.01) { 385 if (empty($CFG->keepmessagingallusersenabled)) { 386 // When it is not set, $CFG->messagingallusers should be disabled by default. 387 // When $CFG->messagingallusers = false, the default user preference is MESSAGE_PRIVACY_COURSEMEMBER 388 // (contacted by users sharing a course). 389 set_config('messagingallusers', false); 390 } else { 391 // When $CFG->keepmessagingallusersenabled is set to true, $CFG->messagingallusers is set to true. 392 set_config('messagingallusers', true); 393 394 // When $CFG->messagingallusers = true, the default user preference is MESSAGE_PRIVACY_SITE 395 // (contacted by all users site). So we need to set existing values from 0 (MESSAGE_PRIVACY_COURSEMEMBER) 396 // to 2 (MESSAGE_PRIVACY_SITE). 397 $DB->set_field( 398 'user_preferences', 399 'value', 400 \core_message\api::MESSAGE_PRIVACY_SITE, 401 array('name' => 'message_blocknoncontacts', 'value' => 0) 402 ); 403 } 404 405 // Main savepoint reached. 406 upgrade_main_savepoint(true, 2018101700.01); 407 } 408 409 if ($oldversion < 2018101800.00) { 410 // Define table 'favourite' to be created. 411 $table = new xmldb_table('favourite'); 412 413 // Adding fields to table favourite. 414 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 415 $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null); 416 $table->add_field('itemtype', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null); 417 $table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 418 $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 419 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 420 $table->add_field('ordering', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 421 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 422 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 423 424 // Adding keys to table favourite. 425 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 426 $table->add_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']); 427 $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']); 428 429 // Adding indexes to table favourite. 430 $table->add_index('uniqueuserfavouriteitem', XMLDB_INDEX_UNIQUE, ['component', 'itemtype', 'itemid', 'contextid', 'userid']); 431 432 // Conditionally launch create table for favourite. 433 if (!$dbman->table_exists($table)) { 434 $dbman->create_table($table); 435 } 436 437 // Main savepoint reached. 438 upgrade_main_savepoint(true, 2018101800.00); 439 } 440 441 if ($oldversion < 2018102200.00) { 442 // Add field 'type' to 'message_conversations'. 443 $table = new xmldb_table('message_conversations'); 444 $field = new xmldb_field('type', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 1, 'id'); 445 if (!$dbman->field_exists($table, $field)) { 446 $dbman->add_field($table, $field); 447 } 448 449 // Add field 'name' to 'message_conversations'. 450 $field = new xmldb_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'type'); 451 if (!$dbman->field_exists($table, $field)) { 452 $dbman->add_field($table, $field); 453 } 454 455 // Conditionally launch add index 'type'. 456 $index = new xmldb_index('type', XMLDB_INDEX_NOTUNIQUE, ['type']); 457 if (!$dbman->index_exists($table, $index)) { 458 $dbman->add_index($table, $index); 459 } 460 461 // Define table 'message_conversations' to be updated. 462 $table = new xmldb_table('message_conversations'); 463 464 // Remove the unique 'convhash' index, change to null and add a new non unique index. 465 $index = new xmldb_index('convhash', XMLDB_INDEX_UNIQUE, ['convhash']); 466 if ($dbman->index_exists($table, $index)) { 467 $dbman->drop_index($table, $index); 468 } 469 470 $field = new xmldb_field('convhash', XMLDB_TYPE_CHAR, '40', null, null, null, null, 'name'); 471 $dbman->change_field_notnull($table, $field); 472 473 $index = new xmldb_index('convhash', XMLDB_INDEX_NOTUNIQUE, ['convhash']); 474 if (!$dbman->index_exists($table, $index)) { 475 $dbman->add_index($table, $index); 476 } 477 478 upgrade_main_savepoint(true, 2018102200.00); 479 } 480 481 if ($oldversion < 2018102300.02) { 482 // Alter 'message_conversations' table to support groups. 483 $table = new xmldb_table('message_conversations'); 484 $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'convhash'); 485 if (!$dbman->field_exists($table, $field)) { 486 $dbman->add_field($table, $field); 487 } 488 489 $field = new xmldb_field('itemtype', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'component'); 490 if (!$dbman->field_exists($table, $field)) { 491 $dbman->add_field($table, $field); 492 } 493 494 $field = new xmldb_field('itemid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'itemtype'); 495 if (!$dbman->field_exists($table, $field)) { 496 $dbman->add_field($table, $field); 497 } 498 499 $field = new xmldb_field('contextid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'itemid'); 500 if (!$dbman->field_exists($table, $field)) { 501 $dbman->add_field($table, $field); 502 } 503 504 $field = new xmldb_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, 0, 'contextid'); 505 if (!$dbman->field_exists($table, $field)) { 506 $dbman->add_field($table, $field); 507 } 508 509 $field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'enabled'); 510 if (!$dbman->field_exists($table, $field)) { 511 $dbman->add_field($table, $field); 512 } 513 514 // Add key. 515 $key = new xmldb_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']); 516 $dbman->add_key($table, $key); 517 518 // Add index. 519 $index = new xmldb_index('component-itemtype-itemid-contextid', XMLDB_INDEX_NOTUNIQUE, ['component', 'itemtype', 520 'itemid', 'contextid']); 521 if (!$dbman->index_exists($table, $index)) { 522 $dbman->add_index($table, $index); 523 } 524 525 upgrade_main_savepoint(true, 2018102300.02); 526 } 527 528 if ($oldversion < 2018102900.00) { 529 // Define field predictionsprocessor to be added to analytics_models. 530 $table = new xmldb_table('analytics_models'); 531 $field = new xmldb_field('predictionsprocessor', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'timesplitting'); 532 533 // Conditionally launch add field predictionsprocessor. 534 if (!$dbman->field_exists($table, $field)) { 535 $dbman->add_field($table, $field); 536 } 537 538 // Main savepoint reached. 539 upgrade_main_savepoint(true, 2018102900.00); 540 } 541 542 if ($oldversion < 2018110500.01) { 543 // Define fields to be added to the 'badge' table. 544 $tablebadge = new xmldb_table('badge'); 545 $fieldversion = new xmldb_field('version', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'nextcron'); 546 $fieldlanguage = new xmldb_field('language', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'version'); 547 $fieldimageauthorname = new xmldb_field('imageauthorname', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'language'); 548 $fieldimageauthoremail = new xmldb_field('imageauthoremail', XMLDB_TYPE_CHAR, '255', null, null, 549 null, null, 'imageauthorname'); 550 $fieldimageauthorurl = new xmldb_field('imageauthorurl', XMLDB_TYPE_CHAR, '255', null, null, 551 null, null, 'imageauthoremail'); 552 $fieldimagecaption = new xmldb_field('imagecaption', XMLDB_TYPE_TEXT, null, null, null, null, null, 'imageauthorurl'); 553 554 if (!$dbman->field_exists($tablebadge, $fieldversion)) { 555 $dbman->add_field($tablebadge, $fieldversion); 556 } 557 if (!$dbman->field_exists($tablebadge, $fieldlanguage)) { 558 $dbman->add_field($tablebadge, $fieldlanguage); 559 } 560 if (!$dbman->field_exists($tablebadge, $fieldimageauthorname)) { 561 $dbman->add_field($tablebadge, $fieldimageauthorname); 562 } 563 if (!$dbman->field_exists($tablebadge, $fieldimageauthoremail)) { 564 $dbman->add_field($tablebadge, $fieldimageauthoremail); 565 } 566 if (!$dbman->field_exists($tablebadge, $fieldimageauthorurl)) { 567 $dbman->add_field($tablebadge, $fieldimageauthorurl); 568 } 569 if (!$dbman->field_exists($tablebadge, $fieldimagecaption)) { 570 $dbman->add_field($tablebadge, $fieldimagecaption); 571 } 572 573 // Define table badge_endorsement to be created. 574 $table = new xmldb_table('badge_endorsement'); 575 576 // Adding fields to table badge_endorsement. 577 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 578 $table->add_field('badgeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 579 $table->add_field('issuername', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 580 $table->add_field('issuerurl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 581 $table->add_field('issueremail', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 582 $table->add_field('claimid', XMLDB_TYPE_CHAR, '255', null, null, null, null); 583 $table->add_field('claimcomment', XMLDB_TYPE_TEXT, null, null, null, null, null); 584 $table->add_field('dateissued', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 585 586 // Adding keys to table badge_endorsement. 587 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 588 $table->add_key('endorsementbadge', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']); 589 590 // Conditionally launch create table for badge_endorsement. 591 if (!$dbman->table_exists($table)) { 592 $dbman->create_table($table); 593 } 594 595 // Define table badge_related to be created. 596 $table = new xmldb_table('badge_related'); 597 598 // Adding fields to table badge_related. 599 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 600 $table->add_field('badgeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 601 $table->add_field('relatedbadgeid', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 602 603 // Adding keys to table badge_related. 604 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 605 $table->add_key('badgeid', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']); 606 $table->add_key('relatedbadgeid', XMLDB_KEY_FOREIGN, ['relatedbadgeid'], 'badge', ['id']); 607 $table->add_key('badgeid-relatedbadgeid', XMLDB_KEY_UNIQUE, ['badgeid', 'relatedbadgeid']); 608 609 // Conditionally launch create table for badge_related. 610 if (!$dbman->table_exists($table)) { 611 $dbman->create_table($table); 612 } 613 614 // Define table badge_competencies to be created. 615 $table = new xmldb_table('badge_competencies'); 616 617 // Adding fields to table badge_competencies. 618 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 619 $table->add_field('badgeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 620 $table->add_field('targetname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 621 $table->add_field('targeturl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 622 $table->add_field('targetdescription', XMLDB_TYPE_TEXT, null, null, null, null, null); 623 $table->add_field('targetframework', XMLDB_TYPE_CHAR, '255', null, null, null, null); 624 $table->add_field('targetcode', XMLDB_TYPE_CHAR, '255', null, null, null, null); 625 626 // Adding keys to table badge_competencies. 627 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 628 $table->add_key('competenciesbadge', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']); 629 630 // Conditionally launch create table for badge_competencies. 631 if (!$dbman->table_exists($table)) { 632 $dbman->create_table($table); 633 } 634 635 // Main savepoint reached. 636 upgrade_main_savepoint(true, 2018110500.01); 637 } 638 639 if ($oldversion < 2018110700.01) { 640 // This config setting added and then removed. 641 unset_config('showcourseimages', 'moodlecourse'); 642 643 // Main savepoint reached. 644 upgrade_main_savepoint(true, 2018110700.01); 645 } 646 647 if ($oldversion < 2018111301.00) { 648 // Define field locked to be added to context. 649 $table = new xmldb_table('context'); 650 $field = new xmldb_field('locked', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'depth'); 651 652 // Conditionally launch add field locked. 653 if (!$dbman->field_exists($table, $field)) { 654 $dbman->add_field($table, $field); 655 } 656 657 // Define field locked to be added to context_temp. 658 $table = new xmldb_table('context_temp'); 659 $field = new xmldb_field('locked', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'depth'); 660 661 // Conditionally launch add field locked. 662 if (!$dbman->field_exists($table, $field)) { 663 $dbman->add_field($table, $field); 664 } 665 666 // Note: This change also requires a bump in is_major_upgrade_required. 667 upgrade_main_savepoint(true, 2018111301.00); 668 } 669 670 if ($oldversion < 2018111900.00) { 671 // Update favourited courses, so they are saved in the particular course context instead of the system. 672 $favouritedcourses = $DB->get_records('favourite', ['component' => 'core_course', 'itemtype' => 'courses']); 673 674 foreach ($favouritedcourses as $fc) { 675 $coursecontext = \context_course::instance($fc->itemid); 676 $fc->contextid = $coursecontext->id; 677 $DB->update_record('favourite', $fc); 678 } 679 680 upgrade_main_savepoint(true, 2018111900.00); 681 } 682 683 if ($oldversion < 2018111900.01) { 684 // Define table oauth2_access_token to be created. 685 $table = new xmldb_table('oauth2_access_token'); 686 687 // Adding fields to table oauth2_access_token. 688 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 689 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 690 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 691 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 692 $table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 693 $table->add_field('token', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null); 694 $table->add_field('expires', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 695 $table->add_field('scope', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null); 696 697 // Adding keys to table oauth2_access_token. 698 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 699 $table->add_key('issueridkey', XMLDB_KEY_FOREIGN_UNIQUE, ['issuerid'], 'oauth2_issuer', ['id']); 700 701 // Conditionally launch create table for oauth2_access_token. 702 if (!$dbman->table_exists($table)) { 703 $dbman->create_table($table); 704 } 705 706 // Main savepoint reached. 707 upgrade_main_savepoint(true, 2018111900.01); 708 } 709 710 if ($oldversion < 2018112000.00) { 711 // Update favourited conversations, so they are saved in the proper context instead of the system. 712 $sql = "SELECT f.*, mc.contextid as conversationctx 713 FROM {favourite} f 714 JOIN {message_conversations} mc 715 ON mc.id = f.itemid"; 716 $favouritedconversations = $DB->get_records_sql($sql); 717 foreach ($favouritedconversations as $fc) { 718 if (empty($fc->conversationctx)) { 719 $conversationidctx = \context_user::instance($fc->userid)->id; 720 } else { 721 $conversationidctx = $fc->conversationctx; 722 } 723 724 $DB->set_field('favourite', 'contextid', $conversationidctx, ['id' => $fc->id]); 725 } 726 727 upgrade_main_savepoint(true, 2018112000.00); 728 } 729 730 // Automatically generated Moodle v3.6.0 release upgrade line. 731 // Put any upgrade step following this. 732 733 if ($oldversion < 2018120300.01) { 734 // Update the FB logo URL. 735 $oldurl = 'https://facebookbrand.com/wp-content/themes/fb-branding/prj-fb-branding/assets/images/fb-art.png'; 736 $newurl = 'https://facebookbrand.com/wp-content/uploads/2016/05/flogo_rgb_hex-brc-site-250.png'; 737 738 $updatesql = "UPDATE {oauth2_issuer} 739 SET image = :newimage 740 WHERE " . $DB->sql_compare_text('image', 100). " = :oldimage"; 741 $params = [ 742 'newimage' => $newurl, 743 'oldimage' => $oldurl 744 ]; 745 $DB->execute($updatesql, $params); 746 747 upgrade_main_savepoint(true, 2018120300.01); 748 } 749 750 if ($oldversion < 2018120300.02) { 751 // Set all individual conversations to enabled. 752 $updatesql = "UPDATE {message_conversations} 753 SET enabled = :enabled 754 WHERE type = :type"; 755 $DB->execute($updatesql, ['enabled' => 1, 'type' => 1]); 756 757 upgrade_main_savepoint(true, 2018120300.02); 758 } 759 760 if ($oldversion < 2018120301.02) { 761 upgrade_delete_orphaned_file_records(); 762 upgrade_main_savepoint(true, 2018120301.02); 763 } 764 765 if ($oldversion < 2019011500.00) { 766 // Define table task_log to be created. 767 $table = new xmldb_table('task_log'); 768 769 // Adding fields to table task_log. 770 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 771 $table->add_field('type', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, null); 772 $table->add_field('component', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 773 $table->add_field('classname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 774 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 775 $table->add_field('timestart', XMLDB_TYPE_NUMBER, '20, 10', null, XMLDB_NOTNULL, null, null); 776 $table->add_field('timeend', XMLDB_TYPE_NUMBER, '20, 10', null, XMLDB_NOTNULL, null, null); 777 $table->add_field('dbreads', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 778 $table->add_field('dbwrites', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 779 $table->add_field('result', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, null); 780 781 // Adding keys to table task_log. 782 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 783 784 // Adding indexes to table task_log. 785 $table->add_index('classname', XMLDB_INDEX_NOTUNIQUE, ['classname']); 786 $table->add_index('timestart', XMLDB_INDEX_NOTUNIQUE, ['timestart']); 787 788 // Conditionally launch create table for task_log. 789 if (!$dbman->table_exists($table)) { 790 $dbman->create_table($table); 791 } 792 793 // Main savepoint reached. 794 upgrade_main_savepoint(true, 2019011500.00); 795 } 796 797 if ($oldversion < 2019011501.00) { 798 // Define field output to be added to task_log. 799 $table = new xmldb_table('task_log'); 800 $field = new xmldb_field('output', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null, 'result'); 801 802 // Conditionally launch add field output. 803 if (!$dbman->field_exists($table, $field)) { 804 $dbman->add_field($table, $field); 805 } 806 807 // Main savepoint reached. 808 upgrade_main_savepoint(true, 2019011501.00); 809 } 810 811 if ($oldversion < 2019011801.00) { 812 813 // Define table customfield_category to be created. 814 $table = new xmldb_table('customfield_category'); 815 816 // Adding fields to table customfield_category. 817 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 818 $table->add_field('name', XMLDB_TYPE_CHAR, '400', null, XMLDB_NOTNULL, null, null); 819 $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null); 820 $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 821 $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 822 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 823 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 824 $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null); 825 $table->add_field('area', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null); 826 $table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 827 $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 828 829 // Adding keys to table customfield_category. 830 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 831 $table->add_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']); 832 833 // Adding indexes to table customfield_category. 834 $table->add_index('component_area_itemid', XMLDB_INDEX_NOTUNIQUE, ['component', 'area', 'itemid', 'sortorder']); 835 836 // Conditionally launch create table for customfield_category. 837 if (!$dbman->table_exists($table)) { 838 $dbman->create_table($table); 839 } 840 841 // Define table customfield_field to be created. 842 $table = new xmldb_table('customfield_field'); 843 844 // Adding fields to table customfield_field. 845 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 846 $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null); 847 $table->add_field('name', XMLDB_TYPE_CHAR, '400', null, XMLDB_NOTNULL, null, null); 848 $table->add_field('type', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null); 849 $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null); 850 $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 851 $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 852 $table->add_field('categoryid', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 853 $table->add_field('configdata', XMLDB_TYPE_TEXT, null, null, null, null, null); 854 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 855 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 856 857 // Adding keys to table customfield_field. 858 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 859 $table->add_key('categoryid', XMLDB_KEY_FOREIGN, ['categoryid'], 'customfield_category', ['id']); 860 861 // Adding indexes to table customfield_field. 862 $table->add_index('categoryid_sortorder', XMLDB_INDEX_NOTUNIQUE, ['categoryid', 'sortorder']); 863 864 // Conditionally launch create table for customfield_field. 865 if (!$dbman->table_exists($table)) { 866 $dbman->create_table($table); 867 } 868 869 // Define table customfield_data to be created. 870 $table = new xmldb_table('customfield_data'); 871 872 // Adding fields to table customfield_data. 873 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 874 $table->add_field('fieldid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 875 $table->add_field('instanceid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 876 $table->add_field('intvalue', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 877 $table->add_field('decvalue', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null); 878 $table->add_field('shortcharvalue', XMLDB_TYPE_CHAR, '255', null, null, null, null); 879 $table->add_field('charvalue', XMLDB_TYPE_CHAR, '1333', null, null, null, null); 880 $table->add_field('value', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null); 881 $table->add_field('valueformat', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 882 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 883 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 884 $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 885 886 // Adding keys to table customfield_data. 887 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 888 $table->add_key('fieldid', XMLDB_KEY_FOREIGN, ['fieldid'], 'customfield_field', ['id']); 889 $table->add_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']); 890 891 // Adding indexes to table customfield_data. 892 $table->add_index('instanceid-fieldid', XMLDB_INDEX_UNIQUE, ['instanceid', 'fieldid']); 893 $table->add_index('fieldid-intvalue', XMLDB_INDEX_NOTUNIQUE, ['fieldid', 'intvalue']); 894 $table->add_index('fieldid-shortcharvalue', XMLDB_INDEX_NOTUNIQUE, ['fieldid', 'shortcharvalue']); 895 $table->add_index('fieldid-decvalue', XMLDB_INDEX_NOTUNIQUE, ['fieldid', 'decvalue']); 896 897 // Conditionally launch create table for customfield_data. 898 if (!$dbman->table_exists($table)) { 899 $dbman->create_table($table); 900 } 901 902 upgrade_main_savepoint(true, 2019011801.00); 903 } 904 905 if ($oldversion < 2019011801.01) { 906 907 // Delete all files that have been used in sections, which are already deleted. 908 $sql = "SELECT DISTINCT f.itemid as sectionid, f.contextid 909 FROM {files} f 910 LEFT JOIN {course_sections} s ON f.itemid = s.id 911 WHERE f.component = :component AND f.filearea = :filearea AND s.id IS NULL "; 912 913 $params = [ 914 'component' => 'course', 915 'filearea' => 'section' 916 ]; 917 918 $stalefiles = $DB->get_recordset_sql($sql, $params); 919 920 $fs = get_file_storage(); 921 foreach ($stalefiles as $stalefile) { 922 $fs->delete_area_files($stalefile->contextid, 'course', 'section', $stalefile->sectionid); 923 } 924 $stalefiles->close(); 925 926 upgrade_main_savepoint(true, 2019011801.01); 927 } 928 929 if ($oldversion < 2019011801.02) { 930 // Add index 'useridfrom' to the table 'notifications'. 931 $table = new xmldb_table('notifications'); 932 $index = new xmldb_index('useridfrom', XMLDB_INDEX_NOTUNIQUE, ['useridfrom']); 933 934 if (!$dbman->index_exists($table, $index)) { 935 $dbman->add_index($table, $index); 936 } 937 938 upgrade_main_savepoint(true, 2019011801.02); 939 } 940 941 if ($oldversion < 2019011801.03) { 942 // Remove duplicate entries from group memberships. 943 // Find records with multiple userid/groupid combinations and find the highest ID. 944 // Later we will remove all those entries. 945 $sql = " 946 SELECT MIN(id) as minid, userid, groupid 947 FROM {groups_members} 948 GROUP BY userid, groupid 949 HAVING COUNT(id) > 1"; 950 if ($duplicatedrows = $DB->get_recordset_sql($sql)) { 951 foreach ($duplicatedrows as $row) { 952 $DB->delete_records_select('groups_members', 953 'userid = :userid AND groupid = :groupid AND id <> :minid', (array)$row); 954 } 955 } 956 $duplicatedrows->close(); 957 958 // Define key useridgroupid (unique) to be added to group_members. 959 $table = new xmldb_table('groups_members'); 960 $key = new xmldb_key('useridgroupid', XMLDB_KEY_UNIQUE, array('userid', 'groupid')); 961 // Launch add key useridgroupid. 962 $dbman->add_key($table, $key); 963 // Main savepoint reached. 964 upgrade_main_savepoint(true, 2019011801.03); 965 } 966 967 if ($oldversion < 2019021500.01) { 968 $insights = $DB->get_record('message_providers', ['component' => 'moodle', 'name' => 'insights']); 969 if (!empty($insights)) { 970 $insights->capability = null; 971 $DB->update_record('message_providers', $insights); 972 } 973 upgrade_main_savepoint(true, 2019021500.01); 974 } 975 976 if ($oldversion < 2019021500.02) { 977 // Default 'off' for existing sites as this is the behaviour they had earlier. 978 set_config('messagingdefaultpressenter', false); 979 980 // Main savepoint reached. 981 upgrade_main_savepoint(true, 2019021500.02); 982 } 983 984 if ($oldversion < 2019030100.01) { 985 // Create adhoc task to delete renamed My Course search area (ID core_course-mycourse). 986 $record = new \stdClass(); 987 $record->classname = '\core\task\clean_up_deleted_search_area_task'; 988 $record->component = 'core'; 989 990 // Next run time based from nextruntime computation in \core\task\manager::queue_adhoc_task(). 991 $nextruntime = time() - 1; 992 $record->nextruntime = $nextruntime; 993 $record->customdata = json_encode('core_course-mycourse'); 994 995 $DB->insert_record('task_adhoc', $record); 996 997 // Main savepoint reached. 998 upgrade_main_savepoint(true, 2019030100.01); 999 } 1000 1001 if ($oldversion < 2019030700.01) { 1002 1003 // Define field evaluationmode to be added to analytics_models_log. 1004 $table = new xmldb_table('analytics_models_log'); 1005 $field = new xmldb_field('evaluationmode', XMLDB_TYPE_CHAR, '50', null, null, null, 1006 null, 'version'); 1007 1008 // Conditionally launch add field evaluationmode. 1009 if (!$dbman->field_exists($table, $field)) { 1010 $dbman->add_field($table, $field); 1011 1012 $updatesql = "UPDATE {analytics_models_log} 1013 SET evaluationmode = 'configuration'"; 1014 $DB->execute($updatesql, []); 1015 1016 // Changing nullability of field evaluationmode on table block_instances to not null. 1017 $field = new xmldb_field('evaluationmode', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, 1018 null, null, 'version'); 1019 1020 // Launch change of nullability for field evaluationmode. 1021 $dbman->change_field_notnull($table, $field); 1022 } 1023 1024 // Main savepoint reached. 1025 upgrade_main_savepoint(true, 2019030700.01); 1026 } 1027 1028 if ($oldversion < 2019030800.00) { 1029 // Define table 'message_conversation_actions' to be created. 1030 // Note - I would have preferred 'message_conversation_user_actions' but due to Oracle we can't. Boo. 1031 $table = new xmldb_table('message_conversation_actions'); 1032 1033 // Adding fields to table 'message_conversation_actions'. 1034 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 1035 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 1036 $table->add_field('conversationid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 1037 $table->add_field('action', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 1038 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 1039 1040 // Adding keys to table 'message_conversation_actions'. 1041 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 1042 $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']); 1043 $table->add_key('conversationid', XMLDB_KEY_FOREIGN, ['conversationid'], 'message_conversations', ['id']); 1044 1045 // Conditionally launch create table for 'message_conversation_actions'. 1046 if (!$dbman->table_exists($table)) { 1047 $dbman->create_table($table); 1048 } 1049 1050 // Main savepoint reached. 1051 upgrade_main_savepoint(true, 2019030800.00); 1052 } 1053 1054 if ($oldversion < 2019030800.02) { 1055 // Remove any conversations and their members associated with non-existent groups. 1056 $sql = "SELECT mc.id 1057 FROM {message_conversations} mc 1058 LEFT JOIN {groups} g 1059 ON mc.itemid = g.id 1060 WHERE mc.component = :component 1061 AND mc.itemtype = :itemtype 1062 AND g.id is NULL"; 1063 $conversations = $DB->get_records_sql($sql, ['component' => 'core_group', 'itemtype' => 'groups']); 1064 1065 if ($conversations) { 1066 $conversationids = array_keys($conversations); 1067 1068 $DB->delete_records_list('message_conversations', 'id', $conversationids); 1069 $DB->delete_records_list('message_conversation_members', 'conversationid', $conversationids); 1070 $DB->delete_records_list('message_conversation_actions', 'conversationid', $conversationids); 1071 1072 // Now, go through each conversation and delete any messages and related message actions. 1073 foreach ($conversationids as $conversationid) { 1074 if ($messages = $DB->get_records('messages', ['conversationid' => $conversationid])) { 1075 $messageids = array_keys($messages); 1076 1077 // Delete the actions. 1078 list($insql, $inparams) = $DB->get_in_or_equal($messageids); 1079 $DB->delete_records_select('message_user_actions', "messageid $insql", $inparams); 1080 1081 // Delete the messages. 1082 $DB->delete_records('messages', ['conversationid' => $conversationid]); 1083 } 1084 } 1085 } 1086 1087 // Main savepoint reached. 1088 upgrade_main_savepoint(true, 2019030800.02); 1089 } 1090 1091 if ($oldversion < 2019030800.03) { 1092 1093 // Add missing indicators to course_dropout. 1094 $params = [ 1095 'target' => '\core\analytics\target\course_dropout', 1096 'trained' => 0, 1097 'enabled' => 0, 1098 ]; 1099 $models = $DB->get_records('analytics_models', $params); 1100 foreach ($models as $model) { 1101 $indicators = json_decode($model->indicators); 1102 1103 $potentiallymissingindicators = [ 1104 '\core_course\analytics\indicator\completion_enabled', 1105 '\core_course\analytics\indicator\potential_cognitive_depth', 1106 '\core_course\analytics\indicator\potential_social_breadth', 1107 '\core\analytics\indicator\any_access_after_end', 1108 '\core\analytics\indicator\any_access_before_start', 1109 '\core\analytics\indicator\any_write_action_in_course', 1110 '\core\analytics\indicator\read_actions' 1111 ]; 1112 1113 $missing = false; 1114 foreach ($potentiallymissingindicators as $potentiallymissingindicator) { 1115 if (!in_array($potentiallymissingindicator, $indicators)) { 1116 // Add the missing indicator to sites upgraded before 2017072000.02. 1117 $indicators[] = $potentiallymissingindicator; 1118 $missing = true; 1119 } 1120 } 1121 1122 if ($missing) { 1123 $model->indicators = json_encode($indicators); 1124 $model->version = time(); 1125 $model->timemodified = time(); 1126 $DB->update_record('analytics_models', $model); 1127 } 1128 } 1129 1130 // Add missing indicators to no_teaching. 1131 $params = [ 1132 'target' => '\core\analytics\target\no_teaching', 1133 ]; 1134 $models = $DB->get_records('analytics_models', $params); 1135 foreach ($models as $model) { 1136 $indicators = json_decode($model->indicators); 1137 if (!in_array('\core_course\analytics\indicator\no_student', $indicators)) { 1138 // Add the missing indicator to sites upgraded before 2017072000.02. 1139 1140 $indicators[] = '\core_course\analytics\indicator\no_student'; 1141 1142 $model->indicators = json_encode($indicators); 1143 $model->version = time(); 1144 $model->timemodified = time(); 1145 $DB->update_record('analytics_models', $model); 1146 } 1147 } 1148 1149 // Main savepoint reached. 1150 upgrade_main_savepoint(true, 2019030800.03); 1151 } 1152 1153 if ($oldversion < 2019031500.01) { 1154 1155 $defaulttimesplittings = get_config('analytics', 'timesplittings'); 1156 if ($defaulttimesplittings !== false) { 1157 set_config('defaulttimesplittingsevaluation', $defaulttimesplittings, 'analytics'); 1158 unset_config('timesplittings', 'analytics'); 1159 } 1160 1161 // Main savepoint reached. 1162 upgrade_main_savepoint(true, 2019031500.01); 1163 } 1164 1165 if ($oldversion < 2019032200.02) { 1166 // The no_teaching model might have been marked as not-trained by mistake (static models are always trained). 1167 $DB->set_field('analytics_models', 'trained', 1, ['target' => '\core\analytics\target\no_teaching']); 1168 upgrade_main_savepoint(true, 2019032200.02); 1169 } 1170 1171 if ($oldversion < 2019032900.00) { 1172 1173 // Define table badge_competencies to be renamed to badge_alignment. 1174 $table = new xmldb_table('badge_competencies'); 1175 1176 // Be careful if this step gets run twice. 1177 if ($dbman->table_exists($table)) { 1178 $key = new xmldb_key('competenciesbadge', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']); 1179 1180 // Launch drop key competenciesbadge. 1181 $dbman->drop_key($table, $key); 1182 1183 $key = new xmldb_key('alignmentsbadge', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']); 1184 1185 // Launch add key alignmentsbadge. 1186 $dbman->add_key($table, $key); 1187 1188 // Launch rename table for badge_alignment. 1189 $dbman->rename_table($table, 'badge_alignment'); 1190 } 1191 1192 upgrade_main_savepoint(true, 2019032900.00); 1193 } 1194 1195 if ($oldversion < 2019032900.01) { 1196 $sql = "UPDATE {task_scheduled} 1197 SET classname = ? 1198 WHERE component = ? 1199 AND classname = ?"; 1200 $DB->execute($sql, [ 1201 '\core\task\question_preview_cleanup_task', 1202 'moodle', 1203 '\core\task\question_cron_task' 1204 ]); 1205 1206 // Main savepoint reached. 1207 upgrade_main_savepoint(true, 2019032900.01); 1208 } 1209 1210 if ($oldversion < 2019040200.01) { 1211 // Removing the themes BSB, Clean, More from core. 1212 // If these theme wish to be retained empty this array before upgrade. 1213 $themes = array('theme_bootstrapbase' => 'bootstrapbase', 1214 'theme_clean' => 'clean', 'theme_more' => 'more'); 1215 foreach ($themes as $key => $theme) { 1216 if (check_dir_exists($CFG->dirroot . '/theme/' . $theme, false)) { 1217 // Ignore the themes that have been re-downloaded. 1218 unset($themes[$key]); 1219 } 1220 } 1221 // Check we actually have themes to remove. 1222 if (count($themes) > 0) { 1223 list($insql, $inparams) = $DB->get_in_or_equal($themes, SQL_PARAMS_NAMED); 1224 1225 // Replace the theme usage. 1226 $DB->set_field_select('course', 'theme', 'classic', "theme $insql", $inparams); 1227 $DB->set_field_select('course_categories', 'theme', 'classic', "theme $insql", $inparams); 1228 $DB->set_field_select('user', 'theme', 'classic', "theme $insql", $inparams); 1229 $DB->set_field_select('mnet_host', 'theme', 'classic', "theme $insql", $inparams); 1230 $DB->set_field_select('cohort', 'theme', 'classic', "theme $insql", $inparams); 1231 1232 // Replace the theme configs. 1233 if (in_array(get_config('core', 'theme'), $themes)) { 1234 set_config('theme', 'classic'); 1235 } 1236 if (in_array(get_config('core', 'thememobile'), $themes)) { 1237 set_config('thememobile', 'classic'); 1238 } 1239 if (in_array(get_config('core', 'themelegacy'), $themes)) { 1240 set_config('themelegacy', 'classic'); 1241 } 1242 if (in_array(get_config('core', 'themetablet'), $themes)) { 1243 set_config('themetablet', 'classic'); 1244 } 1245 1246 // Hacky emulation of plugin uninstallation. 1247 foreach ($themes as $key => $theme) { 1248 unset_all_config_for_plugin($key); 1249 } 1250 } 1251 1252 // Main savepoint reached. 1253 upgrade_main_savepoint(true, 2019040200.01); 1254 } 1255 1256 if ($oldversion < 2019040600.02) { 1257 1258 // Define key fileid (foreign) to be dropped form analytics_train_samples. 1259 $table = new xmldb_table('analytics_train_samples'); 1260 $key = new xmldb_key('fileid', XMLDB_KEY_FOREIGN, ['fileid'], 'files', ['id']); 1261 1262 // Launch drop key fileid. 1263 $dbman->drop_key($table, $key); 1264 1265 // Define field fileid to be dropped from analytics_train_samples. 1266 $table = new xmldb_table('analytics_train_samples'); 1267 $field = new xmldb_field('fileid'); 1268 1269 // Conditionally launch drop field fileid. 1270 if ($dbman->field_exists($table, $field)) { 1271 $dbman->drop_field($table, $field); 1272 } 1273 1274 // Main savepoint reached. 1275 upgrade_main_savepoint(true, 2019040600.02); 1276 } 1277 1278 if ($oldversion < 2019040600.04) { 1279 // Define field and index to be added to backup_controllers. 1280 $table = new xmldb_table('backup_controllers'); 1281 $field = new xmldb_field('progress', XMLDB_TYPE_NUMBER, '15, 14', null, XMLDB_NOTNULL, null, '0', 'timemodified'); 1282 $index = new xmldb_index('useritem_ix', XMLDB_INDEX_NOTUNIQUE, ['userid', 'itemid']); 1283 // Conditionally launch add field progress. 1284 if (!$dbman->field_exists($table, $field)) { 1285 $dbman->add_field($table, $field); 1286 } 1287 // Conditionally launch add index useritem_ix. 1288 if (!$dbman->index_exists($table, $index)) { 1289 $dbman->add_index($table, $index); 1290 } 1291 1292 // Main savepoint reached. 1293 upgrade_main_savepoint(true, 2019040600.04); 1294 } 1295 1296 if ($oldversion < 2019041000.02) { 1297 1298 // Define field fullmessagetrust to be added to messages. 1299 $table = new xmldb_table('messages'); 1300 $field = new xmldb_field('fullmessagetrust', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'timecreated'); 1301 1302 // Conditionally launch add field fullmessagetrust. 1303 if (!$dbman->field_exists($table, $field)) { 1304 $dbman->add_field($table, $field); 1305 } 1306 1307 // Main savepoint reached. 1308 upgrade_main_savepoint(true, 2019041000.02); 1309 } 1310 1311 if ($oldversion < 2019041300.01) { 1312 // Add the field 'name' to the 'analytics_models' table. 1313 $table = new xmldb_table('analytics_models'); 1314 $field = new xmldb_field('name', XMLDB_TYPE_CHAR, '1333', null, null, null, null, 'trained'); 1315 1316 if (!$dbman->field_exists($table, $field)) { 1317 $dbman->add_field($table, $field); 1318 } 1319 // Main savepoint reached. 1320 upgrade_main_savepoint(true, 2019041300.01); 1321 } 1322 1323 if ($oldversion < 2019041800.01) { 1324 // STEP 1. For the existing and migrated self-conversations, set the type to the new MESSAGE_CONVERSATION_TYPE_SELF, update 1325 // the convhash and star them. 1326 $sql = "SELECT mcm.conversationid, mcm.userid, MAX(mcm.id) as maxid 1327 FROM {message_conversation_members} mcm 1328 INNER JOIN {user} u ON mcm.userid = u.id 1329 WHERE u.deleted = 0 1330 GROUP BY mcm.conversationid, mcm.userid 1331 HAVING COUNT(*) > 1"; 1332 $selfconversationsrs = $DB->get_recordset_sql($sql); 1333 $maxids = []; 1334 foreach ($selfconversationsrs as $selfconversation) { 1335 $DB->update_record('message_conversations', 1336 ['id' => $selfconversation->conversationid, 1337 'type' => \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, 1338 'convhash' => \core_message\helper::get_conversation_hash([$selfconversation->userid]) 1339 ] 1340 ); 1341 1342 // Star the existing self-conversation. 1343 $favouriterecord = new \stdClass(); 1344 $favouriterecord->component = 'core_message'; 1345 $favouriterecord->itemtype = 'message_conversations'; 1346 $favouriterecord->itemid = $selfconversation->conversationid; 1347 $userctx = \context_user::instance($selfconversation->userid); 1348 $favouriterecord->contextid = $userctx->id; 1349 $favouriterecord->userid = $selfconversation->userid; 1350 if (!$DB->record_exists('favourite', (array)$favouriterecord)) { 1351 $favouriterecord->timecreated = time(); 1352 $favouriterecord->timemodified = $favouriterecord->timecreated; 1353 $DB->insert_record('favourite', $favouriterecord); 1354 } 1355 1356 // Set the self-conversation member with maxid to remove it later. 1357 $maxids[] = $selfconversation->maxid; 1358 } 1359 $selfconversationsrs->close(); 1360 1361 // Remove the repeated member with the higher id for all the existing self-conversations. 1362 if (!empty($maxids)) { 1363 list($insql, $inparams) = $DB->get_in_or_equal($maxids); 1364 $DB->delete_records_select('message_conversation_members', "id $insql", $inparams); 1365 } 1366 1367 // STEP 2. Migrate existing self-conversation relying on old message tables, setting the type to the new 1368 // MESSAGE_CONVERSATION_TYPE_SELF and the convhash to the proper one. Star them also. 1369 1370 // On the messaging legacy tables, self-conversations are only present in the 'message_read' table, so we don't need to 1371 // check the content in the 'message' table. 1372 $sql = "SELECT mr.* 1373 FROM {message_read} mr 1374 INNER JOIN {user} u ON mr.useridfrom = u.id 1375 WHERE mr.useridfrom = mr.useridto AND mr.notification = 0 AND u.deleted = 0"; 1376 $legacyselfmessagesrs = $DB->get_recordset_sql($sql); 1377 foreach ($legacyselfmessagesrs as $message) { 1378 // Get the self-conversation or create and star it if doesn't exist. 1379 $conditions = [ 1380 'type' => \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, 1381 'convhash' => \core_message\helper::get_conversation_hash([$message->useridfrom]) 1382 ]; 1383 $selfconversation = $DB->get_record('message_conversations', $conditions); 1384 if (empty($selfconversation)) { 1385 // Create the self-conversation. 1386 $selfconversation = new \stdClass(); 1387 $selfconversation->type = \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF; 1388 $selfconversation->convhash = \core_message\helper::get_conversation_hash([$message->useridfrom]); 1389 $selfconversation->enabled = 1; 1390 $selfconversation->timecreated = time(); 1391 $selfconversation->timemodified = $selfconversation->timecreated; 1392 1393 $selfconversation->id = $DB->insert_record('message_conversations', $selfconversation); 1394 1395 // Add user to this self-conversation. 1396 $member = new \stdClass(); 1397 $member->conversationid = $selfconversation->id; 1398 $member->userid = $message->useridfrom; 1399 $member->timecreated = time(); 1400 1401 $member->id = $DB->insert_record('message_conversation_members', $member); 1402 1403 // Star the self-conversation. 1404 $favouriterecord = new \stdClass(); 1405 $favouriterecord->component = 'core_message'; 1406 $favouriterecord->itemtype = 'message_conversations'; 1407 $favouriterecord->itemid = $selfconversation->id; 1408 $userctx = \context_user::instance($message->useridfrom); 1409 $favouriterecord->contextid = $userctx->id; 1410 $favouriterecord->userid = $message->useridfrom; 1411 if (!$DB->record_exists('favourite', (array)$favouriterecord)) { 1412 $favouriterecord->timecreated = time(); 1413 $favouriterecord->timemodified = $favouriterecord->timecreated; 1414 $DB->insert_record('favourite', $favouriterecord); 1415 } 1416 } 1417 1418 // Create the object we will be inserting into the database. 1419 $tabledata = new \stdClass(); 1420 $tabledata->useridfrom = $message->useridfrom; 1421 $tabledata->conversationid = $selfconversation->id; 1422 $tabledata->subject = $message->subject; 1423 $tabledata->fullmessage = $message->fullmessage; 1424 $tabledata->fullmessageformat = $message->fullmessageformat ?? FORMAT_MOODLE; 1425 $tabledata->fullmessagehtml = $message->fullmessagehtml; 1426 $tabledata->smallmessage = $message->smallmessage; 1427 $tabledata->timecreated = $message->timecreated; 1428 1429 $messageid = $DB->insert_record('messages', $tabledata); 1430 1431 // Check if we need to mark this message as deleted (self-conversations add this information on the 1432 // timeuserfromdeleted field. 1433 if ($message->timeuserfromdeleted) { 1434 $mua = new \stdClass(); 1435 $mua->userid = $message->useridfrom; 1436 $mua->messageid = $messageid; 1437 $mua->action = \core_message\api::MESSAGE_ACTION_DELETED; 1438 $mua->timecreated = $message->timeuserfromdeleted; 1439 1440 $DB->insert_record('message_user_actions', $mua); 1441 } 1442 1443 // Mark this message as read. 1444 $mua = new \stdClass(); 1445 $mua->userid = $message->useridto; 1446 $mua->messageid = $messageid; 1447 $mua->action = \core_message\api::MESSAGE_ACTION_READ; 1448 $mua->timecreated = $message->timeread; 1449 1450 $DB->insert_record('message_user_actions', $mua); 1451 1452 // The self-conversation message has been migrated. Delete the record from the legacy table as soon as possible 1453 // to avoid migrate it twice. 1454 $DB->delete_records('message_read', ['id' => $message->id]); 1455 } 1456 $legacyselfmessagesrs->close(); 1457 1458 // Main savepoint reached. 1459 upgrade_main_savepoint(true, 2019041800.01); 1460 } 1461 1462 if ($oldversion < 2019042200.01) { 1463 1464 // Define table role_sortorder to be dropped. 1465 $table = new xmldb_table('role_sortorder'); 1466 1467 // Conditionally launch drop table for role_sortorder. 1468 if ($dbman->table_exists($table)) { 1469 $dbman->drop_table($table); 1470 } 1471 1472 // Main savepoint reached. 1473 upgrade_main_savepoint(true, 2019042200.01); 1474 } 1475 1476 if ($oldversion < 2019042200.02) { 1477 1478 // Let's update all (old core) targets to their new (core_course) locations. 1479 $targets = [ 1480 '\core\analytics\target\course_competencies' => '\core_course\analytics\target\course_competencies', 1481 '\core\analytics\target\course_completion' => '\core_course\analytics\target\course_completion', 1482 '\core\analytics\target\course_dropout' => '\core_course\analytics\target\course_dropout', 1483 '\core\analytics\target\course_gradetopass' => '\core_course\analytics\target\course_gradetopass', 1484 '\core\analytics\target\no_teaching' => '\core_course\analytics\target\no_teaching', 1485 ]; 1486 1487 foreach ($targets as $oldclass => $newclass) { 1488 $DB->set_field('analytics_models', 'target', $newclass, ['target' => $oldclass]); 1489 } 1490 1491 // Main savepoint reached. 1492 upgrade_main_savepoint(true, 2019042200.02); 1493 } 1494 1495 if ($oldversion < 2019042300.01) { 1496 $sql = "UPDATE {capabilities} 1497 SET name = ?, 1498 contextlevel = ? 1499 WHERE name = ?"; 1500 $DB->execute($sql, ['moodle/category:viewcourselist', CONTEXT_COURSECAT, 'moodle/course:browse']); 1501 1502 $sql = "UPDATE {role_capabilities} 1503 SET capability = ? 1504 WHERE capability = ?"; 1505 $DB->execute($sql, ['moodle/category:viewcourselist', 'moodle/course:browse']); 1506 1507 // Main savepoint reached. 1508 upgrade_main_savepoint(true, 2019042300.01); 1509 } 1510 1511 if ($oldversion < 2019042300.03) { 1512 1513 // Add new customdata field to message table. 1514 $table = new xmldb_table('message'); 1515 $field = new xmldb_field('customdata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'eventtype'); 1516 1517 // Conditionally launch add field output. 1518 if (!$dbman->field_exists($table, $field)) { 1519 $dbman->add_field($table, $field); 1520 } 1521 1522 // Add new customdata field to notifications and messages table. 1523 $table = new xmldb_table('notifications'); 1524 $field = new xmldb_field('customdata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'timecreated'); 1525 1526 // Conditionally launch add field output. 1527 if (!$dbman->field_exists($table, $field)) { 1528 $dbman->add_field($table, $field); 1529 } 1530 1531 $table = new xmldb_table('messages'); 1532 // Conditionally launch add field output. 1533 if (!$dbman->field_exists($table, $field)) { 1534 $dbman->add_field($table, $field); 1535 } 1536 1537 // Main savepoint reached. 1538 upgrade_main_savepoint(true, 2019042300.03); 1539 } 1540 1541 if ($oldversion < 2019042700.01) { 1542 1543 // Define field firstanalysis to be added to analytics_used_analysables. 1544 $table = new xmldb_table('analytics_used_analysables'); 1545 1546 // Declaring it as null initially (although it is NOT NULL). 1547 $field = new xmldb_field('firstanalysis', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'analysableid'); 1548 1549 // Conditionally launch add field firstanalysis. 1550 if (!$dbman->field_exists($table, $field)) { 1551 $dbman->add_field($table, $field); 1552 1553 // Set existing values to the current timeanalysed value. 1554 $recordset = $DB->get_recordset('analytics_used_analysables'); 1555 foreach ($recordset as $record) { 1556 $record->firstanalysis = $record->timeanalysed; 1557 $DB->update_record('analytics_used_analysables', $record); 1558 } 1559 $recordset->close(); 1560 1561 // Now make the field 'NOT NULL'. 1562 $field = new xmldb_field('firstanalysis', XMLDB_TYPE_INTEGER, '10', 1563 null, XMLDB_NOTNULL, null, null, 'analysableid'); 1564 $dbman->change_field_notnull($table, $field); 1565 } 1566 1567 // Main savepoint reached. 1568 upgrade_main_savepoint(true, 2019042700.01); 1569 } 1570 1571 if ($oldversion < 2019050300.01) { 1572 // Delete all stale favourite records which were left behind when a course was deleted. 1573 $params = ['component' => 'core_message', 'itemtype' => 'message_conversations']; 1574 $sql = "SELECT fav.id as id 1575 FROM {favourite} fav 1576 LEFT JOIN {context} ctx ON (ctx.id = fav.contextid) 1577 WHERE fav.component = :component 1578 AND fav.itemtype = :itemtype 1579 AND ctx.id IS NULL"; 1580 1581 if ($records = $DB->get_fieldset_sql($sql, $params)) { 1582 // Just for safety, delete by chunks. 1583 $chunks = array_chunk($records, 1000); 1584 foreach ($chunks as $chunk) { 1585 list($insql, $inparams) = $DB->get_in_or_equal($chunk); 1586 $DB->delete_records_select('favourite', "id $insql", $inparams); 1587 } 1588 } 1589 1590 upgrade_main_savepoint(true, 2019050300.01); 1591 } 1592 1593 if ($oldversion < 2019050600.00) { 1594 1595 // Define field apiversion to be added to badge_backpack. 1596 $table = new xmldb_table('badge_backpack'); 1597 $field = new xmldb_field('apiversion', XMLDB_TYPE_CHAR, '12', null, XMLDB_NOTNULL, null, '1.0', 'password'); 1598 1599 // Conditionally launch add field apiversion. 1600 if (!$dbman->field_exists($table, $field)) { 1601 $dbman->add_field($table, $field); 1602 } 1603 1604 // Define table badge_external_backpack to be created. 1605 $table = new xmldb_table('badge_external_backpack'); 1606 1607 // Adding fields to table badge_external_backpack. 1608 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 1609 $table->add_field('backpackapiurl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 1610 $table->add_field('backpackweburl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 1611 $table->add_field('apiversion', XMLDB_TYPE_CHAR, '12', null, XMLDB_NOTNULL, null, '1.0'); 1612 $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 1613 $table->add_field('password', XMLDB_TYPE_CHAR, '255', null, null, null, null); 1614 1615 // Adding keys to table badge_external_backpack. 1616 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 1617 $table->add_key('backpackapiurlkey', XMLDB_KEY_UNIQUE, ['backpackapiurl']); 1618 $table->add_key('backpackweburlkey', XMLDB_KEY_UNIQUE, ['backpackweburl']); 1619 1620 // Conditionally launch create table for badge_external_backpack. 1621 if (!$dbman->table_exists($table)) { 1622 $dbman->create_table($table); 1623 } 1624 1625 // Define field entityid to be added to badge_external. 1626 $table = new xmldb_table('badge_external'); 1627 $field = new xmldb_field('entityid', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'collectionid'); 1628 1629 // Conditionally launch add field entityid. 1630 if (!$dbman->field_exists($table, $field)) { 1631 $dbman->add_field($table, $field); 1632 } 1633 1634 // Define table badge_external_identifier to be created. 1635 $table = new xmldb_table('badge_external_identifier'); 1636 1637 // Adding fields to table badge_external_identifier. 1638 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 1639 $table->add_field('sitebackpackid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 1640 $table->add_field('internalid', XMLDB_TYPE_CHAR, '128', null, XMLDB_NOTNULL, null, null); 1641 $table->add_field('externalid', XMLDB_TYPE_CHAR, '128', null, XMLDB_NOTNULL, null, null); 1642 $table->add_field('type', XMLDB_TYPE_CHAR, '16', null, XMLDB_NOTNULL, null, null); 1643 1644 // Adding keys to table badge_external_identifier. 1645 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 1646 $table->add_key('fk_backpackid', XMLDB_KEY_FOREIGN, ['sitebackpackid'], 'badge_backpack', ['id']); 1647 $table->add_key('backpack-internal-external', XMLDB_KEY_UNIQUE, ['sitebackpackid', 'internalid', 'externalid', 'type']); 1648 1649 // Conditionally launch create table for badge_external_identifier. 1650 if (!$dbman->table_exists($table)) { 1651 $dbman->create_table($table); 1652 } 1653 1654 // Define field externalbackpackid to be added to badge_backpack. 1655 $table = new xmldb_table('badge_backpack'); 1656 $field = new xmldb_field('externalbackpackid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'password'); 1657 1658 // Conditionally launch add field externalbackpackid. 1659 if (!$dbman->field_exists($table, $field)) { 1660 $dbman->add_field($table, $field); 1661 } 1662 1663 // Define key externalbackpack (foreign) to be added to badge_backpack. 1664 $key = new xmldb_key('externalbackpack', XMLDB_KEY_FOREIGN, ['externalbackpackid'], 'badge_external_backpack', ['id']); 1665 1666 // Launch add key externalbackpack. 1667 $dbman->add_key($table, $key); 1668 1669 $field = new xmldb_field('apiversion'); 1670 1671 // Conditionally launch drop field apiversion. 1672 if ($dbman->field_exists($table, $field)) { 1673 $dbman->drop_field($table, $field); 1674 } 1675 1676 $field = new xmldb_field('backpackurl'); 1677 1678 // Conditionally launch drop field backpackurl. 1679 if ($dbman->field_exists($table, $field)) { 1680 $dbman->drop_field($table, $field); 1681 } 1682 1683 // Add default backpacks. 1684 require_once($CFG->dirroot . '/badges/upgradelib.php'); // Core install and upgrade related functions only for badges. 1685 badges_install_default_backpacks(); 1686 1687 // Main savepoint reached. 1688 upgrade_main_savepoint(true, 2019050600.00); 1689 } 1690 1691 if ($oldversion < 2019051300.01) { 1692 $DB->set_field('analytics_models', 'enabled', '1', ['target' => '\core_user\analytics\target\upcoming_activities_due']); 1693 1694 // Main savepoint reached. 1695 upgrade_main_savepoint(true, 2019051300.01); 1696 } 1697 1698 // Automatically generated Moodle v3.7.0 release upgrade line. 1699 // Put any upgrade step following this. 1700 1701 if ($oldversion < 2019060600.02) { 1702 // Renaming 'opentogoogle' config to 'opentowebcrawlers'. 1703 $opentogooglevalue = get_config('core', 'opentogoogle'); 1704 1705 // Move the value over if it was previously configured. 1706 if ($opentogooglevalue !== false) { 1707 set_config('opentowebcrawlers', $opentogooglevalue); 1708 } 1709 1710 // Remove the now unused value. 1711 unset_config('opentogoogle'); 1712 1713 // Main savepoint reached. 1714 upgrade_main_savepoint(true, 2019060600.02); 1715 } 1716 1717 if ($oldversion < 2019062900.00) { 1718 // Debugsmtp is now only available via config.php. 1719 $DB->delete_records('config', array('name' => 'debugsmtp')); 1720 1721 // Main savepoint reached. 1722 upgrade_main_savepoint(true, 2019062900.00); 1723 } 1724 1725 if ($oldversion < 2019070400.01) { 1726 1727 $basecolors = ['#81ecec', '#74b9ff', '#a29bfe', '#dfe6e9', '#00b894', 1728 '#0984e3', '#b2bec3', '#fdcb6e', '#fd79a8', '#6c5ce7']; 1729 1730 $colornr = 1; 1731 foreach ($basecolors as $color) { 1732 set_config('coursecolor' . $colornr, $color, 'core_admin'); 1733 $colornr++; 1734 } 1735 1736 upgrade_main_savepoint(true, 2019070400.01); 1737 } 1738 1739 if ($oldversion < 2019072200.00) { 1740 1741 // Define field relativedatesmode to be added to course. 1742 $table = new xmldb_table('course'); 1743 $field = new xmldb_field('relativedatesmode', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'enddate'); 1744 1745 // Conditionally launch add field relativedatesmode. 1746 if (!$dbman->field_exists($table, $field)) { 1747 $dbman->add_field($table, $field); 1748 } 1749 1750 // Main savepoint reached. 1751 upgrade_main_savepoint(true, 2019072200.00); 1752 } 1753 1754 if ($oldversion < 2019072500.01) { 1755 // Remove the "popup" processor from the list of default processors for the messagecontactrequests notification. 1756 $oldloggedinconfig = get_config('message', 'message_provider_moodle_messagecontactrequests_loggedin'); 1757 $oldloggedoffconfig = get_config('message', 'message_provider_moodle_messagecontactrequests_loggedoff'); 1758 $newloggedinconfig = implode(',', array_filter(explode(',', $oldloggedinconfig), function($value) { 1759 return $value != 'popup'; 1760 })); 1761 $newloggedoffconfig = implode(',', array_filter(explode(',', $oldloggedoffconfig), function($value) { 1762 return $value != 'popup'; 1763 })); 1764 set_config('message_provider_moodle_messagecontactrequests_loggedin', $newloggedinconfig, 'message'); 1765 set_config('message_provider_moodle_messagecontactrequests_loggedoff', $newloggedoffconfig, 'message'); 1766 1767 upgrade_main_savepoint(true, 2019072500.01); 1768 } 1769 1770 if ($oldversion < 2019072500.03) { 1771 unset_config('httpswwwroot'); 1772 1773 upgrade_main_savepoint(true, 2019072500.03); 1774 } 1775 1776 if ($oldversion < 2019073100.00) { 1777 // Update the empty tag instructions to null. 1778 $instructions = get_config('core', 'auth_instructions'); 1779 1780 if (trim(html_to_text($instructions)) === '') { 1781 set_config('auth_instructions', ''); 1782 } 1783 1784 // Main savepoint reached. 1785 upgrade_main_savepoint(true, 2019073100.00); 1786 } 1787 1788 if ($oldversion < 2019083000.01) { 1789 1790 // If block_community is no longer present, remove it. 1791 if (!file_exists($CFG->dirroot . '/blocks/community/communitycourse.php')) { 1792 // Drop table that is no longer needed. 1793 $table = new xmldb_table('block_community'); 1794 if ($dbman->table_exists($table)) { 1795 $dbman->drop_table($table); 1796 } 1797 1798 // Delete instances. 1799 $instances = $DB->get_records_list('block_instances', 'blockname', ['community']); 1800 $instanceids = array_keys($instances); 1801 1802 if (!empty($instanceids)) { 1803 $DB->delete_records_list('block_positions', 'blockinstanceid', $instanceids); 1804 $DB->delete_records_list('block_instances', 'id', $instanceids); 1805 list($sql, $params) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED); 1806 $params['contextlevel'] = CONTEXT_BLOCK; 1807 $DB->delete_records_select('context', "contextlevel=:contextlevel AND instanceid " . $sql, $params); 1808 1809 $preferences = array(); 1810 foreach ($instances as $instanceid => $instance) { 1811 $preferences[] = 'block' . $instanceid . 'hidden'; 1812 $preferences[] = 'docked_block_instance_' . $instanceid; 1813 } 1814 $DB->delete_records_list('user_preferences', 'name', $preferences); 1815 } 1816 1817 // Delete the block from the block table. 1818 $DB->delete_records('block', array('name' => 'community')); 1819 1820 // Remove capabilities. 1821 capabilities_cleanup('block_community'); 1822 // Clean config. 1823 unset_all_config_for_plugin('block_community'); 1824 1825 // Remove Moodle-level community based capabilities. 1826 $capabilitiestoberemoved = ['block/community:addinstance', 'block/community:myaddinstance']; 1827 // Delete any role_capabilities for the old roles. 1828 $DB->delete_records_list('role_capabilities', 'capability', $capabilitiestoberemoved); 1829 // Delete the capability itself. 1830 $DB->delete_records_list('capabilities', 'name', $capabilitiestoberemoved); 1831 } 1832 1833 upgrade_main_savepoint(true, 2019083000.01); 1834 } 1835 1836 if ($oldversion < 2019083000.02) { 1837 // Remove unused config. 1838 unset_config('enablecoursepublishing'); 1839 upgrade_main_savepoint(true, 2019083000.02); 1840 } 1841 1842 if ($oldversion < 2019083000.04) { 1843 // Delete "orphaned" subscriptions. 1844 $sql = "SELECT DISTINCT es.userid 1845 FROM {event_subscriptions} es 1846 LEFT JOIN {user} u ON u.id = es.userid 1847 WHERE u.deleted = 1 OR u.id IS NULL"; 1848 $deletedusers = $DB->get_fieldset_sql($sql); 1849 if ($deletedusers) { 1850 list($sql, $params) = $DB->get_in_or_equal($deletedusers); 1851 1852 // Delete orphaned subscriptions. 1853 $DB->execute("DELETE FROM {event_subscriptions} WHERE userid " . $sql, $params); 1854 } 1855 1856 upgrade_main_savepoint(true, 2019083000.04); 1857 } 1858 1859 if ($oldversion < 2019090500.01) { 1860 1861 // Define index analysableid (not unique) to be added to analytics_used_analysables. 1862 $table = new xmldb_table('analytics_used_analysables'); 1863 $index = new xmldb_index('analysableid', XMLDB_INDEX_NOTUNIQUE, ['analysableid']); 1864 1865 // Conditionally launch add index analysableid. 1866 if (!$dbman->index_exists($table, $index)) { 1867 $dbman->add_index($table, $index); 1868 } 1869 1870 // Main savepoint reached. 1871 upgrade_main_savepoint(true, 2019090500.01); 1872 } 1873 1874 if ($oldversion < 2019092700.01) { 1875 upgrade_rename_prediction_actions_useful_incorrectly_flagged(); 1876 upgrade_main_savepoint(true, 2019092700.01); 1877 } 1878 1879 if ($oldversion < 2019100800.02) { 1880 // Rename the official moodle sites directory the site is registered with. 1881 $DB->execute("UPDATE {registration_hubs} 1882 SET hubname = ?, huburl = ? 1883 WHERE huburl = ?", ['moodle', 'https://stats.moodle.org', 'https://moodle.net']); 1884 1885 // Convert the hub site specific settings to the new naming format without the hub URL in the name. 1886 $hubconfig = get_config('hub'); 1887 1888 if (!empty($hubconfig)) { 1889 foreach (upgrade_convert_hub_config_site_param_names($hubconfig, 'https://moodle.net') as $name => $value) { 1890 set_config($name, $value, 'hub'); 1891 } 1892 } 1893 1894 upgrade_main_savepoint(true, 2019100800.02); 1895 } 1896 1897 if ($oldversion < 2019100900.00) { 1898 // If block_participants is no longer present, remove it. 1899 if (!file_exists($CFG->dirroot . '/blocks/participants/block_participants.php')) { 1900 // Delete instances. 1901 $instances = $DB->get_records_list('block_instances', 'blockname', ['participants']); 1902 $instanceids = array_keys($instances); 1903 1904 if (!empty($instanceids)) { 1905 $DB->delete_records_list('block_positions', 'blockinstanceid', $instanceids); 1906 $DB->delete_records_list('block_instances', 'id', $instanceids); 1907 list($sql, $params) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED); 1908 $params['contextlevel'] = CONTEXT_BLOCK; 1909 $DB->delete_records_select('context', "contextlevel=:contextlevel AND instanceid " . $sql, $params); 1910 1911 $preferences = array(); 1912 foreach ($instances as $instanceid => $instance) { 1913 $preferences[] = 'block' . $instanceid . 'hidden'; 1914 $preferences[] = 'docked_block_instance_' . $instanceid; 1915 } 1916 $DB->delete_records_list('user_preferences', 'name', $preferences); 1917 } 1918 1919 // Delete the block from the block table. 1920 $DB->delete_records('block', array('name' => 'participants')); 1921 1922 // Remove capabilities. 1923 capabilities_cleanup('block_participants'); 1924 1925 // Clean config. 1926 unset_all_config_for_plugin('block_participants'); 1927 } 1928 1929 upgrade_main_savepoint(true, 2019100900.00); 1930 } 1931 1932 if ($oldversion < 2019101600.01) { 1933 1934 // Change the setting $CFG->requestcategoryselection into $CFG->lockrequestcategory with opposite value. 1935 set_config('lockrequestcategory', empty($CFG->requestcategoryselection)); 1936 1937 upgrade_main_savepoint(true, 2019101600.01); 1938 } 1939 1940 if ($oldversion < 2019101800.02) { 1941 1942 // Get the table by its previous name. 1943 $table = new xmldb_table('analytics_models'); 1944 if ($dbman->table_exists($table)) { 1945 1946 // Define field contextids to be added to analytics_models. 1947 $field = new xmldb_field('contextids', XMLDB_TYPE_TEXT, null, null, null, null, null, 'version'); 1948 1949 // Conditionally launch add field contextids. 1950 if (!$dbman->field_exists($table, $field)) { 1951 $dbman->add_field($table, $field); 1952 } 1953 } 1954 1955 // Main savepoint reached. 1956 upgrade_main_savepoint(true, 2019101800.02); 1957 } 1958 1959 if ($oldversion < 2019102500.04) { 1960 // Define table h5p_libraries to be created. 1961 $table = new xmldb_table('h5p_libraries'); 1962 1963 // Adding fields to table h5p_libraries. 1964 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 1965 $table->add_field('machinename', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 1966 $table->add_field('title', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 1967 $table->add_field('majorversion', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, null); 1968 $table->add_field('minorversion', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, null); 1969 $table->add_field('patchversion', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, null); 1970 $table->add_field('runnable', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, null); 1971 $table->add_field('fullscreen', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0'); 1972 $table->add_field('embedtypes', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 1973 $table->add_field('preloadedjs', XMLDB_TYPE_TEXT, null, null, null, null, null); 1974 $table->add_field('preloadedcss', XMLDB_TYPE_TEXT, null, null, null, null, null); 1975 $table->add_field('droplibrarycss', XMLDB_TYPE_TEXT, null, null, null, null, null); 1976 $table->add_field('semantics', XMLDB_TYPE_TEXT, null, null, null, null, null); 1977 $table->add_field('addto', XMLDB_TYPE_TEXT, null, null, null, null, null); 1978 1979 // Adding keys to table h5p_libraries. 1980 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 1981 1982 // Adding indexes to table h5p_libraries. 1983 $table->add_index('machinemajorminorpatch', XMLDB_INDEX_NOTUNIQUE, 1984 ['machinename', 'majorversion', 'minorversion', 'patchversion', 'runnable']); 1985 1986 // Conditionally launch create table for h5p_libraries. 1987 if (!$dbman->table_exists($table)) { 1988 $dbman->create_table($table); 1989 } 1990 1991 // Define table h5p_library_dependencies to be created. 1992 $table = new xmldb_table('h5p_library_dependencies'); 1993 1994 // Adding fields to table h5p_library_dependencies. 1995 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 1996 $table->add_field('libraryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 1997 $table->add_field('requiredlibraryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 1998 $table->add_field('dependencytype', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 1999 2000 // Adding keys to table h5p_library_dependencies. 2001 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 2002 $table->add_key('libraryid', XMLDB_KEY_FOREIGN, ['libraryid'], 'h5p_libraries', ['id']); 2003 $table->add_key('requiredlibraryid', XMLDB_KEY_FOREIGN, ['requiredlibraryid'], 'h5p_libraries', ['id']); 2004 2005 // Conditionally launch create table for h5p_library_dependencies. 2006 if (!$dbman->table_exists($table)) { 2007 $dbman->create_table($table); 2008 } 2009 2010 // Define table h5p to be created. 2011 $table = new xmldb_table('h5p'); 2012 2013 // Adding fields to table h5p. 2014 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 2015 $table->add_field('jsoncontent', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null); 2016 $table->add_field('mainlibraryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2017 $table->add_field('displayoptions', XMLDB_TYPE_INTEGER, '4', null, null, null, null); 2018 $table->add_field('pathnamehash', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null); 2019 $table->add_field('contenthash', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null); 2020 $table->add_field('filtered', XMLDB_TYPE_TEXT, null, null, null, null, null); 2021 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 2022 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 2023 2024 // Adding keys to table h5p. 2025 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 2026 $table->add_key('mainlibraryid', XMLDB_KEY_FOREIGN, ['mainlibraryid'], 'h5p_libraries', ['id']); 2027 2028 // Conditionally launch create table for h5p. 2029 if (!$dbman->table_exists($table)) { 2030 $dbman->create_table($table); 2031 } 2032 2033 // Define table h5p_contents_libraries to be created. 2034 $table = new xmldb_table('h5p_contents_libraries'); 2035 2036 // Adding fields to table h5p_contents_libraries. 2037 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 2038 $table->add_field('h5pid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2039 $table->add_field('libraryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2040 $table->add_field('dependencytype', XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null); 2041 $table->add_field('dropcss', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, null); 2042 $table->add_field('weight', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2043 2044 // Adding keys to table h5p_contents_libraries. 2045 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 2046 $table->add_key('h5pid', XMLDB_KEY_FOREIGN, ['h5pid'], 'h5p', ['id']); 2047 $table->add_key('libraryid', XMLDB_KEY_FOREIGN, ['libraryid'], 'h5p_libraries', ['id']); 2048 2049 // Conditionally launch create table for h5p_contents_libraries. 2050 if (!$dbman->table_exists($table)) { 2051 $dbman->create_table($table); 2052 } 2053 2054 // Define table h5p_libraries_cachedassets to be created. 2055 $table = new xmldb_table('h5p_libraries_cachedassets'); 2056 2057 // Adding fields to table h5p_libraries_cachedassets. 2058 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 2059 $table->add_field('libraryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2060 $table->add_field('hash', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 2061 2062 // Adding keys to table h5p_libraries_cachedassets. 2063 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 2064 $table->add_key('libraryid', XMLDB_KEY_FOREIGN, ['libraryid'], 'h5p_libraries_cachedassets', ['id']); 2065 2066 // Conditionally launch create table for h5p_libraries_cachedassets. 2067 if (!$dbman->table_exists($table)) { 2068 $dbman->create_table($table); 2069 } 2070 2071 // Main savepoint reached. 2072 upgrade_main_savepoint(true, 2019102500.04); 2073 } 2074 2075 if ($oldversion < 2019103000.13) { 2076 2077 upgrade_analytics_fix_contextids_defaults(); 2078 2079 // Main savepoint reached. 2080 upgrade_main_savepoint(true, 2019103000.13); 2081 } 2082 2083 if ($oldversion < 2019111300.00) { 2084 2085 // Define field coremajor to be added to h5p_libraries. 2086 $table = new xmldb_table('h5p_libraries'); 2087 $field = new xmldb_field('coremajor', XMLDB_TYPE_INTEGER, '4', null, null, null, null, 'addto'); 2088 2089 // Conditionally launch add field coremajor. 2090 if (!$dbman->field_exists($table, $field)) { 2091 $dbman->add_field($table, $field); 2092 } 2093 2094 $field = new xmldb_field('coreminor', XMLDB_TYPE_INTEGER, '4', null, null, null, null, 'coremajor'); 2095 2096 // Conditionally launch add field coreminor. 2097 if (!$dbman->field_exists($table, $field)) { 2098 $dbman->add_field($table, $field); 2099 } 2100 2101 // Main savepoint reached. 2102 upgrade_main_savepoint(true, 2019111300.00); 2103 } 2104 2105 // Automatically generated Moodle v3.8.0 release upgrade line. 2106 // Put any upgrade step following this. 2107 2108 if ($oldversion < 2019120500.01) { 2109 // Delete any role assignments for roles which no longer exist. 2110 $DB->delete_records_select('role_assignments', "roleid NOT IN (SELECT id FROM {role})"); 2111 2112 // Main savepoint reached. 2113 upgrade_main_savepoint(true, 2019120500.01); 2114 } 2115 2116 if ($oldversion < 2019121800.00) { 2117 // Upgrade MIME types for existing streaming files. 2118 $filetypes = array( 2119 '%.fmp4' => 'video/mp4', 2120 '%.ts' => 'video/MP2T', 2121 '%.mpd' => 'application/dash+xml', 2122 '%.m3u8' => 'application/x-mpegURL', 2123 ); 2124 2125 $select = $DB->sql_like('filename', '?', false); 2126 foreach ($filetypes as $extension => $mimetype) { 2127 $DB->set_field_select( 2128 'files', 2129 'mimetype', 2130 $mimetype, 2131 $select, 2132 array($extension) 2133 ); 2134 } 2135 2136 upgrade_main_savepoint(true, 2019121800.00); 2137 } 2138 2139 if ($oldversion < 2019122000.01) { 2140 // Clean old upgrade setting not used anymore. 2141 unset_config('linkcoursesectionsupgradescriptwasrun'); 2142 upgrade_main_savepoint(true, 2019122000.01); 2143 } 2144 2145 if ($oldversion < 2020010900.02) { 2146 $table = new xmldb_table('event'); 2147 2148 // This index will improve the performance when the Events API retrieves category and group events. 2149 $index = new xmldb_index('eventtype', XMLDB_INDEX_NOTUNIQUE, ['eventtype']); 2150 if (!$dbman->index_exists($table, $index)) { 2151 $dbman->add_index($table, $index); 2152 } 2153 2154 // This index improves the performance of backups, deletion and visibilty changes on activities. 2155 $index = new xmldb_index('modulename-instance', XMLDB_INDEX_NOTUNIQUE, ['modulename', 'instance']); 2156 if (!$dbman->index_exists($table, $index)) { 2157 $dbman->add_index($table, $index); 2158 } 2159 2160 upgrade_main_savepoint(true, 2020010900.02); 2161 } 2162 2163 if ($oldversion < 2020011700.02) { 2164 // Delete all orphaned subscription events. 2165 $select = "subscriptionid IS NOT NULL 2166 AND subscriptionid NOT IN (SELECT id from {event_subscriptions})"; 2167 $DB->delete_records_select('event', $select); 2168 2169 upgrade_main_savepoint(true, 2020011700.02); 2170 } 2171 2172 if ($oldversion < 2020013000.01) { 2173 global $DB; 2174 // Delete any associated files. 2175 $fs = get_file_storage(); 2176 $sql = "SELECT cuc.id, cuc.userid 2177 FROM {competency_usercomp} cuc 2178 LEFT JOIN {user} u ON cuc.userid = u.id 2179 WHERE u.deleted = 1"; 2180 $usercompetencies = $DB->get_records_sql($sql); 2181 foreach ($usercompetencies as $usercomp) { 2182 $DB->delete_records('competency_evidence', ['usercompetencyid' => $usercomp->id]); 2183 $DB->delete_records('competency_usercompcourse', ['userid' => $usercomp->userid]); 2184 $DB->delete_records('competency_usercompplan', ['userid' => $usercomp->userid]); 2185 $DB->delete_records('competency_usercomp', ['userid' => $usercomp->userid]); 2186 } 2187 2188 $sql = "SELECT cue.id, cue.userid 2189 FROM {competency_userevidence} cue 2190 LEFT JOIN {user} u ON cue.userid = u.id 2191 WHERE u.deleted = 1"; 2192 $userevidences = $DB->get_records_sql($sql); 2193 foreach ($userevidences as $userevidence) { 2194 $DB->delete_records('competency_userevidencecomp', ['userevidenceid' => $userevidence->id]); 2195 $DB->delete_records('competency_userevidence', ['id' => $userevidence->id]); 2196 2197 if ($record = $DB->get_record('context', ['contextlevel' => CONTEXT_USER, 'instanceid' => $userevidence->userid], 2198 '*', IGNORE_MISSING)) { 2199 // Delete all orphaned user evidences files. 2200 $fs->delete_area_files($record->id, 'core_competency', 'userevidence', $userevidence->userid); 2201 } 2202 } 2203 2204 $sql = "SELECT cp.id 2205 FROM {competency_plan} cp 2206 LEFT JOIN {user} u ON cp.userid = u.id 2207 WHERE u.deleted = 1"; 2208 $userplans = $DB->get_records_sql($sql); 2209 foreach ($userplans as $userplan) { 2210 $DB->delete_records('competency_plancomp', ['planid' => $userplan->id]); 2211 $DB->delete_records('competency_plan', ['id' => $userplan->id]); 2212 } 2213 2214 // Main savepoint reached. 2215 upgrade_main_savepoint(true, 2020013000.01); 2216 } 2217 2218 if ($oldversion < 2020040200.01) { 2219 // Clean up completion criteria records referring to courses that no longer exist. 2220 $select = 'criteriatype = :type AND courseinstance NOT IN (SELECT id FROM {course})'; 2221 $params = ['type' => 8]; // COMPLETION_CRITERIA_TYPE_COURSE. 2222 2223 $DB->delete_records_select('course_completion_criteria', $select, $params); 2224 2225 // Main savepoint reached. 2226 upgrade_main_savepoint(true, 2020040200.01); 2227 } 2228 2229 if ($oldversion < 2020040700.00) { 2230 // Remove deprecated Mozilla OpenBadges backpack. 2231 $url = 'https://backpack.openbadges.org'; 2232 $bp = $DB->get_record('badge_external_backpack', ['backpackapiurl' => $url]); 2233 if ($bp) { 2234 // Remove connections for users to this backpack. 2235 $sql = "SELECT DISTINCT bb.id 2236 FROM {badge_backpack} bb 2237 LEFT JOIN {badge_external} be ON be. backpackid = bb.externalbackpackid 2238 WHERE bb.externalbackpackid = :backpackid"; 2239 $params = ['backpackid' => $bp->id]; 2240 $externalbackpacks = $DB->get_fieldset_sql($sql, $params); 2241 if ($externalbackpacks) { 2242 list($sql, $params) = $DB->get_in_or_equal($externalbackpacks); 2243 2244 // Delete user external collections references to this backpack. 2245 $DB->execute("DELETE FROM {badge_external} WHERE backpackid " . $sql, $params); 2246 } 2247 $DB->delete_records('badge_backpack', ['externalbackpackid' => $bp->id]); 2248 2249 // Delete deprecated backpack entry. 2250 $DB->delete_records('badge_external_backpack', ['backpackapiurl' => $url]); 2251 } 2252 2253 // Set active external backpack to Badgr.io. 2254 $url = 'https://api.badgr.io/v2'; 2255 if ($bp = $DB->get_record('badge_external_backpack', ['backpackapiurl' => $url])) { 2256 set_config('badges_site_backpack', $bp->id); 2257 } else { 2258 unset_config('badges_site_backpack'); 2259 } 2260 2261 upgrade_main_savepoint(true, 2020040700.00); 2262 } 2263 2264 if ($oldversion < 2020041500.00) { 2265 // Define table to store contentbank contents. 2266 $table = new xmldb_table('contentbank_content'); 2267 2268 // Adding fields to table content_bank. 2269 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 2270 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 2271 $table->add_field('contenttype', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null); 2272 $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2273 $table->add_field('instanceid', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 2274 $table->add_field('configdata', XMLDB_TYPE_TEXT, null, null, null, null, null); 2275 $table->add_field('usercreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2276 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 2277 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 2278 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, '0'); 2279 2280 // Adding keys to table contentbank_content. 2281 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 2282 $table->add_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']); 2283 $table->add_key('usermodified', XMLDB_KEY_FOREIGN, ['usermodified'], 'user', ['id']); 2284 $table->add_key('usercreated', XMLDB_KEY_FOREIGN, ['usercreated'], 'user', ['id']); 2285 2286 // Adding indexes to table contentbank_content. 2287 $table->add_index('name', XMLDB_INDEX_NOTUNIQUE, ['name']); 2288 $table->add_index('instance', XMLDB_INDEX_NOTUNIQUE, ['contextid', 'contenttype', 'instanceid']); 2289 2290 if (!$dbman->table_exists($table)) { 2291 $dbman->create_table($table); 2292 } 2293 2294 // Main savepoint reached. 2295 upgrade_main_savepoint(true, 2020041500.00); 2296 } 2297 2298 if ($oldversion < 2020041700.01) { 2299 // Upgrade h5p MIME type for existing h5p files. 2300 $select = $DB->sql_like('filename', '?', false); 2301 $DB->set_field_select( 2302 'files', 2303 'mimetype', 2304 'application/zip.h5p', 2305 $select, 2306 array('%.h5p') 2307 ); 2308 2309 upgrade_main_savepoint(true, 2020041700.01); 2310 } 2311 2312 if ($oldversion < 2020042800.01) { 2313 // Delete obsolete config value. 2314 unset_config('enablesafebrowserintegration'); 2315 // Clean up config of the old plugin. 2316 unset_all_config_for_plugin('quizaccess_safebrowser'); 2317 2318 upgrade_main_savepoint(true, 2020042800.01); 2319 } 2320 2321 if ($oldversion < 2020051900.01) { 2322 // Define field component to be added to event. 2323 $table = new xmldb_table('event'); 2324 $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'repeatid'); 2325 2326 // Conditionally launch add field component. 2327 if (!$dbman->field_exists($table, $field)) { 2328 $dbman->add_field($table, $field); 2329 } 2330 2331 // Define index component (not unique) to be added to event. 2332 $table = new xmldb_table('event'); 2333 $index = new xmldb_index('component', XMLDB_INDEX_NOTUNIQUE, ['component', 'eventtype', 'instance']); 2334 2335 // Conditionally launch add index component. 2336 if (!$dbman->index_exists($table, $index)) { 2337 $dbman->add_index($table, $index); 2338 } 2339 2340 // Main savepoint reached. 2341 upgrade_main_savepoint(true, 2020051900.01); 2342 } 2343 2344 if ($oldversion < 2020052000.00) { 2345 // Define table badge_backpack_oauth2 to be created. 2346 $table = new xmldb_table('badge_backpack_oauth2'); 2347 2348 // Adding fields to table badge_backpack_oauth2. 2349 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 2350 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 2351 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 2352 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 2353 $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2354 $table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2355 $table->add_field('externalbackpackid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 2356 $table->add_field('token', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null); 2357 $table->add_field('refreshtoken', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null); 2358 $table->add_field('expires', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 2359 $table->add_field('scope', XMLDB_TYPE_TEXT, null, null, null, null, null); 2360 2361 // Adding keys to table badge_backpack_oauth2. 2362 $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); 2363 $table->add_key('usermodified', XMLDB_KEY_FOREIGN, ['usermodified'], 'user', ['id']); 2364 $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']); 2365 $table->add_key('issuerid', XMLDB_KEY_FOREIGN, ['issuerid'], 'oauth2_issuer', ['id']); 2366 $table->add_key('externalbackpackid', XMLDB_KEY_FOREIGN, ['externalbackpackid'], 'badge_external_backpack', ['id']); 2367 // Conditionally launch create table for badge_backpack_oauth2. 2368 if (!$dbman->table_exists($table)) { 2369 $dbman->create_table($table); 2370 } 2371 2372 // Define field oauth2_issuerid to be added to badge_external_backpack. 2373 $tablebadgeexternalbackpack = new xmldb_table('badge_external_backpack'); 2374 $fieldoauth2issuerid = new xmldb_field('oauth2_issuerid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'password'); 2375 $keybackpackoauth2key = new xmldb_key('backpackoauth2key', XMLDB_KEY_FOREIGN, ['oauth2_issuerid'], 'oauth2_issuer', ['id']); 2376 2377 // Conditionally launch add field oauth2_issuerid. 2378 if (!$dbman->field_exists($tablebadgeexternalbackpack, $fieldoauth2issuerid)) { 2379 $dbman->add_field($tablebadgeexternalbackpack, $fieldoauth2issuerid); 2380 2381 // Launch add key backpackoauth2key. 2382 $dbman->add_key($tablebadgeexternalbackpack, $keybackpackoauth2key); 2383 } 2384 2385 // Define field assertion to be added to badge_external. 2386 $tablebadgeexternal = new xmldb_table('badge_external'); 2387 $fieldassertion = new xmldb_field('assertion', XMLDB_TYPE_TEXT, null, null, null, null, null, 'entityid'); 2388 2389 // Conditionally launch add field assertion. 2390 if (!$dbman->field_exists($tablebadgeexternal, $fieldassertion)) { 2391 $dbman->add_field($tablebadgeexternal, $fieldassertion); 2392 } 2393 2394 // Main savepoint reached. 2395 upgrade_main_savepoint(true, 2020052000.00); 2396 } 2397 2398 if ($oldversion < 2020052200.01) { 2399 2400 // Define field custom to be added to license. 2401 $table = new xmldb_table('license'); 2402 $field = new xmldb_field('custom', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0'); 2403 2404 // Conditionally launch add field custom. 2405 if (!$dbman->field_exists($table, $field)) { 2406 $dbman->add_field($table, $field); 2407 } 2408 2409 // Define field sortorder to be added to license. 2410 $field = new xmldb_field('sortorder', XMLDB_TYPE_INTEGER, '5', null, XMLDB_NOTNULL, null, '0'); 2411 2412 // Conditionally launch add field sortorder. 2413 if (!$dbman->field_exists($table, $field)) { 2414 $dbman->add_field($table, $field); 2415 } 2416 2417 // Define index license (not unique) to be added to files. 2418 $table = new xmldb_table('files'); 2419 $index = new xmldb_index('license', XMLDB_INDEX_NOTUNIQUE, ['license']); 2420 2421 // Conditionally launch add index license. 2422 if (!$dbman->index_exists($table, $index)) { 2423 $dbman->add_index($table, $index); 2424 } 2425 2426 // Upgrade the core license details. 2427 upgrade_core_licenses(); 2428 2429 // Main savepoint reached. 2430 upgrade_main_savepoint(true, 2020052200.01); 2431 } 2432 2433 if ($oldversion < 2020060500.01) { 2434 // Define field moodlenetprofile to be added to user. 2435 $table = new xmldb_table('user'); 2436 $field = new xmldb_field('moodlenetprofile', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'alternatename'); 2437 2438 // Conditionally launch add field moodlenetprofile. 2439 if (!$dbman->field_exists($table, $field)) { 2440 $dbman->add_field($table, $field); 2441 } 2442 2443 // Main savepoint reached. 2444 upgrade_main_savepoint(true, 2020060500.01); 2445 } 2446 2447 // Automatically generated Moodle v3.9.0 release upgrade line. 2448 // Put any upgrade step following this. 2449 if ($oldversion < 2020061500.02) { 2450 // Update default digital age consent map according to the current legislation on each country. 2451 2452 // The default age of digital consent map for 38 and below. 2453 $oldageofdigitalconsentmap = implode(PHP_EOL, [ 2454 '*, 16', 2455 'AT, 14', 2456 'ES, 14', 2457 'US, 13' 2458 ]); 2459 2460 // Check if the current age of digital consent map matches the old one. 2461 if (get_config('moodle', 'agedigitalconsentmap') === $oldageofdigitalconsentmap) { 2462 // If the site is still using the old defaults, upgrade to the new default. 2463 $ageofdigitalconsentmap = implode(PHP_EOL, [ 2464 '*, 16', 2465 'AT, 14', 2466 'BE, 13', 2467 'BG, 14', 2468 'CY, 14', 2469 'CZ, 15', 2470 'DK, 13', 2471 'EE, 13', 2472 'ES, 14', 2473 'FI, 13', 2474 'FR, 15', 2475 'GB, 13', 2476 'GR, 15', 2477 'IT, 14', 2478 'LT, 14', 2479 'LV, 13', 2480 'MT, 13', 2481 'NO, 13', 2482 'PT, 13', 2483 'SE, 13', 2484 'US, 13' 2485 ]); 2486 set_config('agedigitalconsentmap', $ageofdigitalconsentmap); 2487 } 2488 2489 upgrade_main_savepoint(true, 2020061500.02); 2490 } 2491 2492 if ($oldversion < 2020061501.01) { 2493 // Clean up completion criteria records referring to NULL course prerequisites. 2494 $select = 'criteriatype = :type AND courseinstance IS NULL'; 2495 $params = ['type' => 8]; // COMPLETION_CRITERIA_TYPE_COURSE. 2496 2497 $DB->delete_records_select('course_completion_criteria', $select, $params); 2498 2499 // Main savepoint reached. 2500 upgrade_main_savepoint(true, 2020061501.01); 2501 } 2502 2503 if ($oldversion < 2020061501.04) { 2504 // Restore and set the guest user if it has been previously removed via GDPR, or set to an nonexistent 2505 // user account. 2506 $currentguestuser = $DB->get_record('user', array('id' => $CFG->siteguest)); 2507 2508 if (!$currentguestuser) { 2509 if (!$guest = $DB->get_record('user', array('username' => 'guest', 'mnethostid' => $CFG->mnet_localhost_id))) { 2510 // Create a guest user account. 2511 $guest = new stdClass(); 2512 $guest->auth = 'manual'; 2513 $guest->username = 'guest'; 2514 $guest->password = hash_internal_user_password('guest'); 2515 $guest->firstname = get_string('guestuser'); 2516 $guest->lastname = ' '; 2517 $guest->email = 'root@localhost'; 2518 $guest->description = get_string('guestuserinfo'); 2519 $guest->mnethostid = $CFG->mnet_localhost_id; 2520 $guest->confirmed = 1; 2521 $guest->lang = $CFG->lang; 2522 $guest->timemodified= time(); 2523 $guest->id = $DB->insert_record('user', $guest); 2524 } 2525 // Set the guest user. 2526 set_config('siteguest', $guest->id); 2527 } 2528 2529 // Main savepoint reached. 2530 upgrade_main_savepoint(true, 2020061501.04); 2531 } 2532 2533 if ($oldversion < 2020061501.09) { 2534 // Delete all user evidence files from users that have been deleted. 2535 $sql = "SELECT DISTINCT f.* 2536 FROM {files} f 2537 LEFT JOIN {context} c ON f.contextid = c.id 2538 WHERE f.component = :component 2539 AND f.filearea = :filearea 2540 AND c.id IS NULL"; 2541 $stalefiles = $DB->get_records_sql($sql, ['component' => 'core_competency', 'filearea' => 'userevidence']); 2542 2543 $fs = get_file_storage(); 2544 foreach ($stalefiles as $stalefile) { 2545 $fs->get_file_instance($stalefile)->delete(); 2546 } 2547 2548 upgrade_main_savepoint(true, 2020061501.09); 2549 } 2550 2551 if ($oldversion < 2020061501.11) { 2552 2553 // Define field metadatasettings to be added to h5p_libraries. 2554 $table = new xmldb_table('h5p_libraries'); 2555 $field = new xmldb_field('metadatasettings', XMLDB_TYPE_TEXT, null, null, null, null, null, 'coreminor'); 2556 2557 // Conditionally launch add field metadatasettings. 2558 if (!$dbman->field_exists($table, $field)) { 2559 $dbman->add_field($table, $field); 2560 } 2561 2562 // Get installed library files that have no metadata settings value. 2563 $params = [ 2564 'component' => 'core_h5p', 2565 'filearea' => 'libraries', 2566 'filename' => 'library.json', 2567 ]; 2568 $sql = "SELECT l.id, f.id as fileid 2569 FROM {files} f 2570 LEFT JOIN {h5p_libraries} l ON f.itemid = l.id 2571 WHERE f.component = :component 2572 AND f.filearea = :filearea 2573 AND f.filename = :filename"; 2574 $libraries = $DB->get_records_sql($sql, $params); 2575 2576 // Update metadatasettings field when the attribute is present in the library.json file. 2577 $fs = get_file_storage(); 2578 foreach ($libraries as $library) { 2579 $jsonfile = $fs->get_file_by_id($library->fileid); 2580 $jsoncontent = json_decode($jsonfile->get_content()); 2581 if (isset($jsoncontent->metadataSettings)) { 2582 unset($library->fileid); 2583 $library->metadatasettings = json_encode($jsoncontent->metadataSettings); 2584 $DB->update_record('h5p_libraries', $library); 2585 } 2586 } 2587 2588 // Main savepoint reached. 2589 upgrade_main_savepoint(true, 2020061501.11); 2590 } 2591 2592 if ($oldversion < 2020061502.09) { 2593 // Delete orphaned course_modules_completion rows; these were not deleted properly 2594 // by remove_course_contents function. 2595 $DB->delete_records_select('course_modules_completion', " 2596 NOT EXISTS ( 2597 SELECT 1 2598 FROM {course_modules} cm 2599 WHERE cm.id = {course_modules_completion}.coursemoduleid 2600 )"); 2601 upgrade_main_savepoint(true, 2020061502.09); 2602 } 2603 2604 if ($oldversion < 2020061502.10) { 2605 // Script to fix incorrect records of "hidden" field in existing grade items. 2606 $sql = "SELECT cm.instance, cm.course 2607 FROM {course_modules} cm 2608 JOIN {modules} m ON m.id = cm.module 2609 WHERE m.name = :module AND cm.visible = :visible"; 2610 $hidequizlist = $DB->get_recordset_sql($sql, ['module' => 'quiz', 'visible' => 0]); 2611 2612 foreach ($hidequizlist as $hidequiz) { 2613 $params = [ 2614 'itemmodule' => 'quiz', 2615 'courseid' => $hidequiz->course, 2616 'iteminstance' => $hidequiz->instance, 2617 ]; 2618 2619 $DB->set_field('grade_items', 'hidden', 1, $params); 2620 } 2621 $hidequizlist->close(); 2622 2623 upgrade_main_savepoint(true, 2020061502.10); 2624 } 2625 2626 if ($oldversion < 2020061502.12) { 2627 // Get the current guest user which is also set as 'deleted'. 2628 $guestuser = $DB->get_record('user', ['id' => $CFG->siteguest, 'deleted' => 1]); 2629 // If there is a deleted guest user, reset the user to not be deleted and make sure the related 2630 // user context exists. 2631 if ($guestuser) { 2632 $guestuser->deleted = 0; 2633 $DB->update_record('user', $guestuser); 2634 2635 // Get the guest user context. 2636 $guestusercontext = $DB->get_record('context', 2637 ['contextlevel' => CONTEXT_USER, 'instanceid' => $guestuser->id]); 2638 2639 // If the guest user context does not exist, create it. 2640 if (!$guestusercontext) { 2641 $record = new stdClass(); 2642 $record->contextlevel = CONTEXT_USER; 2643 $record->instanceid = $guestuser->id; 2644 $record->depth = 0; 2645 // The path is not known before insert. 2646 $record->path = null; 2647 $record->locked = 0; 2648 2649 $record->id = $DB->insert_record('context', $record); 2650 2651 // Update the path. 2652 $record->path = '/' . SYSCONTEXTID . '/' . $record->id; 2653 $record->depth = substr_count($record->path, '/'); 2654 $DB->update_record('context', $record); 2655 } 2656 } 2657 2658 // Main savepoint reached. 2659 upgrade_main_savepoint(true, 2020061502.12); 2660 } 2661 2662 if ($oldversion < 2020061502.13) { 2663 // Reset analytics model output dir if it's the default value. 2664 $modeloutputdir = get_config('analytics', 'modeloutputdir'); 2665 if (strcasecmp($modeloutputdir, $CFG->dataroot . DIRECTORY_SEPARATOR . 'models') == 0) { 2666 set_config('modeloutputdir', '', 'analytics'); 2667 } 2668 2669 // Main savepoint reached. 2670 upgrade_main_savepoint(true, 2020061502.13); 2671 } 2672 2673 if ($oldversion < 2020061502.14) { 2674 // Remove all the files with component='core_h5p' and filearea='editor' because they won't be used anymore. 2675 $fs = get_file_storage(); 2676 $syscontext = context_system::instance(); 2677 $fs->delete_area_files($syscontext->id, 'core_h5p', 'editor'); 2678 2679 // Main savepoint reached. 2680 upgrade_main_savepoint(true, 2020061502.14); 2681 } 2682 2683 if ($oldversion < 2020061503.01) { 2684 // Get all lessons that are set with a completion criteria of 'requires grade' but with no grade type set. 2685 $sql = "SELECT cm.id 2686 FROM {course_modules} cm 2687 JOIN {lesson} l ON l.id = cm.instance 2688 JOIN {modules} m ON m.id = cm.module 2689 WHERE m.name = :name AND cm.completiongradeitemnumber IS NOT NULL AND l.grade = :grade"; 2690 2691 do { 2692 if ($invalidconfigrations = $DB->get_records_sql($sql, ['name' => 'lesson', 'grade' => 0], 0, 1000)) { 2693 list($insql, $inparams) = $DB->get_in_or_equal(array_keys($invalidconfigrations), SQL_PARAMS_NAMED); 2694 $DB->set_field_select('course_modules', 'completiongradeitemnumber', null, "id $insql", $inparams); 2695 } 2696 } while ($invalidconfigrations); 2697 2698 upgrade_main_savepoint(true, 2020061503.01); 2699 } 2700 2701 if ($oldversion < 2020061504.07) { 2702 // Get all the external backpacks and update the sortorder column, to avoid repeated/wrong values. As sortorder was not 2703 // used since now, the id column will be the criteria to follow for re-ordering them with a valid value. 2704 $i = 1; 2705 $records = $DB->get_records('badge_external_backpack', null, 'id ASC'); 2706 foreach ($records as $record) { 2707 $record->sortorder = $i++; 2708 $DB->update_record('badge_external_backpack', $record); 2709 } 2710 2711 upgrade_main_savepoint(true, 2020061504.07); 2712 } 2713 2714 if ($oldversion < 2020061506.05) { 2715 require_once($CFG->libdir . '/db/upgradelib.php'); 2716 2717 // Check if this site has executed the problematic upgrade steps. 2718 $needsfixing = upgrade_calendar_site_status(false); 2719 2720 // Only queue the task if this site has been affected by the problematic upgrade step. 2721 if ($needsfixing) { 2722 2723 // Create adhoc task to search and recover orphaned calendar events. 2724 $record = new \stdClass(); 2725 $record->classname = '\core\task\calendar_fix_orphaned_events'; 2726 2727 // Next run time based from nextruntime computation in \core\task\manager::queue_adhoc_task(). 2728 $nextruntime = time() - 1; 2729 $record->nextruntime = $nextruntime; 2730 $DB->insert_record('task_adhoc', $record); 2731 } 2732 2733 // Main savepoint reached. 2734 upgrade_main_savepoint(true, 2020061506.05); 2735 } 2736 2737 return true; 2738 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body