048ae58cb56226fd7ae3cb9d71fc580d7aa8d5bb
[moodle.git] / lib / db / upgrade.php
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/>.
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  */
43 defined('MOODLE_INTERNAL') || die();
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;
90     require_once($CFG->libdir.'/db/upgradelib.php'); // Core Upgrade-related functions.
92     $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes.
94     // Always keep this upgrade step with version being the minimum
95     // allowed version to upgrade from (v3.2.0 right now).
96     if ($oldversion < 2016120500) {
97         // Just in case somebody hacks upgrade scripts or env, we really can not continue.
98         echo("You need to upgrade to 3.2.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, 2016120500);
102     }
104     if ($oldversion < 2016122800.00) {
105         // Find all roles with the coursecreator archetype.
106         $coursecreatorroleids = $DB->get_records('role', array('archetype' => 'coursecreator'), '', 'id');
108         $context = context_system::instance();
109         $capability = 'moodle/site:configview';
111         foreach ($coursecreatorroleids as $roleid => $notused) {
113             // Check that the capability has not already been assigned. If it has then it's either already set
114             // to allow or specifically set to prohibit or prevent.
115             if (!$DB->record_exists('role_capabilities', array('roleid' => $roleid, 'capability' => $capability))) {
116                 // Assign the capability.
117                 $cap = new stdClass();
118                 $cap->contextid    = $context->id;
119                 $cap->roleid       = $roleid;
120                 $cap->capability   = $capability;
121                 $cap->permission   = CAP_ALLOW;
122                 $cap->timemodified = time();
123                 $cap->modifierid   = 0;
125                 $DB->insert_record('role_capabilities', $cap);
126             }
127         }
129         // Main savepoint reached.
130         upgrade_main_savepoint(true, 2016122800.00);
131     }
133     if ($oldversion < 2017020200.01) {
135         // Define index useridfrom_timeuserfromdeleted_notification (not unique) to be added to message.
136         $table = new xmldb_table('message');
137         $index = new xmldb_index('useridfrom_timeuserfromdeleted_notification', XMLDB_INDEX_NOTUNIQUE, array('useridfrom', 'timeuserfromdeleted', 'notification'));
139         // Conditionally launch add index useridfrom_timeuserfromdeleted_notification.
140         if (!$dbman->index_exists($table, $index)) {
141             $dbman->add_index($table, $index);
142         }
144         // Define index useridto_timeusertodeleted_notification (not unique) to be added to message.
145         $index = new xmldb_index('useridto_timeusertodeleted_notification', XMLDB_INDEX_NOTUNIQUE, array('useridto', 'timeusertodeleted', 'notification'));
147         // Conditionally launch add index useridto_timeusertodeleted_notification.
148         if (!$dbman->index_exists($table, $index)) {
149             $dbman->add_index($table, $index);
150         }
152         $index = new xmldb_index('useridto', XMLDB_INDEX_NOTUNIQUE, array('useridto'));
154         // Conditionally launch drop index useridto.
155         if ($dbman->index_exists($table, $index)) {
156             $dbman->drop_index($table, $index);
157         }
159         // Main savepoint reached.
160         upgrade_main_savepoint(true, 2017020200.01);
161     }
163     if ($oldversion < 2017020200.02) {
165         // Define index useridfrom_timeuserfromdeleted_notification (not unique) to be added to message_read.
166         $table = new xmldb_table('message_read');
167         $index = new xmldb_index('useridfrom_timeuserfromdeleted_notification', XMLDB_INDEX_NOTUNIQUE, array('useridfrom', 'timeuserfromdeleted', 'notification'));
169         // Conditionally launch add index useridfrom_timeuserfromdeleted_notification.
170         if (!$dbman->index_exists($table, $index)) {
171             $dbman->add_index($table, $index);
172         }
174         // Define index useridto_timeusertodeleted_notification (not unique) to be added to message_read.
175         $index = new xmldb_index('useridto_timeusertodeleted_notification', XMLDB_INDEX_NOTUNIQUE, array('useridto', 'timeusertodeleted', 'notification'));
177         // Conditionally launch add index useridto_timeusertodeleted_notification.
178         if (!$dbman->index_exists($table, $index)) {
179             $dbman->add_index($table, $index);
180         }
182         $index = new xmldb_index('useridto', XMLDB_INDEX_NOTUNIQUE, array('useridto'));
184         // Conditionally launch drop index useridto.
185         if ($dbman->index_exists($table, $index)) {
186             $dbman->drop_index($table, $index);
187         }
189         // Main savepoint reached.
190         upgrade_main_savepoint(true, 2017020200.02);
191     }
193     if ($oldversion < 2017020901.00) {
195         // Delete "orphaned" block positions. Note, the query does not use indexes (because there are none),
196         // if it runs too long during upgrade you can comment this line - it will leave orphaned records
197         // in the database but they won't bother you.
198         upgrade_block_positions();
200         // Main savepoint reached.
201         upgrade_main_savepoint(true, 2017020901.00);
202     }
204     if ($oldversion < 2017021300.00) {
205         unset_config('loginpasswordautocomplete');
206         upgrade_main_savepoint(true, 2017021300.00);
207     }
209     if ($oldversion < 2017021400.00) {
210         // Define field visibleoncoursepage to be added to course_modules.
211         $table = new xmldb_table('course_modules');
212         $field = new xmldb_field('visibleoncoursepage', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'visible');
214         // Conditionally launch add field visibleoncoursepage.
215         if (!$dbman->field_exists($table, $field)) {
216             $dbman->add_field($table, $field);
217         }
219         // Main savepoint reached.
220         upgrade_main_savepoint(true, 2017021400.00);
221     }
223     if ($oldversion < 2017030700.00) {
225         // Define field priority to be added to event.
226         $table = new xmldb_table('event');
227         $field = new xmldb_field('priority', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'subscriptionid');
229         // Conditionally launch add field priority.
230         if (!$dbman->field_exists($table, $field)) {
231             $dbman->add_field($table, $field);
232         }
234         // Main savepoint reached.
235         upgrade_main_savepoint(true, 2017030700.00);
236     }
238     if ($oldversion < 2017031400.00) {
240         // Define table file_conversion to be created.
241         $table = new xmldb_table('file_conversion');
243         // Adding fields to table file_conversion.
244         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
245         $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
246         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
247         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
248         $table->add_field('sourcefileid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
249         $table->add_field('targetformat', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
250         $table->add_field('status', XMLDB_TYPE_INTEGER, '10', null, null, null, '0');
251         $table->add_field('statusmessage', XMLDB_TYPE_TEXT, null, null, null, null, null);
252         $table->add_field('converter', XMLDB_TYPE_CHAR, '255', null, null, null, null);
253         $table->add_field('destfileid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
254         $table->add_field('data', XMLDB_TYPE_TEXT, null, null, null, null, null);
256         // Adding keys to table file_conversion.
257         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
258         $table->add_key('sourcefileid', XMLDB_KEY_FOREIGN, array('sourcefileid'), 'files', array('id'));
259         $table->add_key('destfileid', XMLDB_KEY_FOREIGN, array('destfileid'), 'files', array('id'));
261         // Conditionally launch create table for file_conversion.
262         if (!$dbman->table_exists($table)) {
263             $dbman->create_table($table);
264         }
266         // Main savepoint reached.
267         upgrade_main_savepoint(true, 2017031400.00);
268     }
270     if ($oldversion < 2017040400.00) {
272         // If block_course_overview is no longer present, replace with block_myoverview.
273         if (!file_exists($CFG->dirroot . '/blocks/course_overview/block_course_overview.php')) {
274             $DB->set_field('block_instances', 'blockname', 'myoverview', array('blockname' => 'course_overview'));
275         }
277         upgrade_main_savepoint(true, 2017040400.00);
278     }
280     if ($oldversion < 2017040401.00) {
282         // If block_course_overview is no longer present, remove it.
283         // Note - we do not need to completely remove the block context etc because we
284         // have replaced all occurrences of block_course_overview with block_myoverview
285         // in the upgrade step above.
286         if (!file_exists($CFG->dirroot . '/blocks/course_overview/block_course_overview.php')) {
287             // Delete the block from the block table.
288             $DB->delete_records('block', array('name' => 'course_overview'));
289             // Remove capabilities.
290             capabilities_cleanup('block_course_overview');
291             // Clean config.
292             unset_all_config_for_plugin('block_course_overview');
293         }
295         upgrade_main_savepoint(true, 2017040401.00);
296     }
298     if ($oldversion < 2017040402.00) {
300         // Define fields to be added to the 'event' table.
301         $table = new xmldb_table('event');
302         $fieldtype = new xmldb_field('type', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, 0, 'instance');
303         $fieldtimesort = new xmldb_field('timesort', XMLDB_TYPE_INTEGER, '10', null, false, null, null, 'timeduration');
305         // Conditionally launch add field.
306         if (!$dbman->field_exists($table, $fieldtype)) {
307             $dbman->add_field($table, $fieldtype);
308         }
310         // Conditionally launch add field.
311         if (!$dbman->field_exists($table, $fieldtimesort)) {
312             $dbman->add_field($table, $fieldtimesort);
313         }
315         // Now, define the index we will be adding.
316         $index = new xmldb_index('type-timesort', XMLDB_INDEX_NOTUNIQUE, array('type', 'timesort'));
318         // Conditionally launch add index.
319         if (!$dbman->index_exists($table, $index)) {
320             $dbman->add_index($table, $index);
321         }
323         upgrade_main_savepoint(true, 2017040402.00);
324     }
326     if ($oldversion < 2017040700.01) {
328         // Define table oauth2_issuer to be created.
329         $table = new xmldb_table('oauth2_issuer');
331         // Adding fields to table oauth2_issuer.
332         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
333         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
334         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
335         $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
336         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
337         $table->add_field('image', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
338         $table->add_field('baseurl', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
339         $table->add_field('clientid', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
340         $table->add_field('clientsecret', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
341         $table->add_field('loginscopes', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
342         $table->add_field('loginscopesoffline', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
343         $table->add_field('loginparams', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
344         $table->add_field('loginparamsoffline', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
345         $table->add_field('alloweddomains', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
346         $table->add_field('scopessupported', XMLDB_TYPE_TEXT, null, null, null, null, null);
347         $table->add_field('showonloginpage', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
348         $table->add_field('enabled', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
349         $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
351         // Adding keys to table oauth2_issuer.
352         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
354         // Conditionally launch create table for oauth2_issuer.
355         if (!$dbman->table_exists($table)) {
356             $dbman->create_table($table);
357         }
359         // Main savepoint reached.
360         upgrade_main_savepoint(true, 2017040700.01);
361     }
363     if ($oldversion < 2017040700.02) {
365         // Define table oauth2_endpoint to be created.
366         $table = new xmldb_table('oauth2_endpoint');
368         // Adding fields to table oauth2_endpoint.
369         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
370         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
371         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
372         $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
373         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
374         $table->add_field('url', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
375         $table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
377         // Adding keys to table oauth2_endpoint.
378         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
379         $table->add_key('issuer_id_key', XMLDB_KEY_FOREIGN, array('issuerid'), 'oauth2_issuer', array('id'));
381         // Conditionally launch create table for oauth2_endpoint.
382         if (!$dbman->table_exists($table)) {
383             $dbman->create_table($table);
384         }
386         // Main savepoint reached.
387         upgrade_main_savepoint(true, 2017040700.02);
388     }
390     if ($oldversion < 2017040700.03) {
392         // Define table oauth2_system_account to be created.
393         $table = new xmldb_table('oauth2_system_account');
395         // Adding fields to table oauth2_system_account.
396         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
397         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
398         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
399         $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
400         $table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
401         $table->add_field('refreshtoken', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
402         $table->add_field('grantedscopes', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
403         $table->add_field('username', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
404         $table->add_field('email', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
406         // Adding keys to table oauth2_system_account.
407         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
408         $table->add_key('issueridkey', XMLDB_KEY_FOREIGN_UNIQUE, array('issuerid'), 'oauth2_issuer', array('id'));
410         // Conditionally launch create table for oauth2_system_account.
411         if (!$dbman->table_exists($table)) {
412             $dbman->create_table($table);
413         }
415         // Main savepoint reached.
416         upgrade_main_savepoint(true, 2017040700.03);
417     }
419     if ($oldversion < 2017040700.04) {
421         // Define table oauth2_user_field_mapping to be created.
422         $table = new xmldb_table('oauth2_user_field_mapping');
424         // Adding fields to table oauth2_user_field_mapping.
425         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
426         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
427         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
428         $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
429         $table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
430         $table->add_field('externalfield', XMLDB_TYPE_CHAR, '64', null, XMLDB_NOTNULL, null, null);
431         $table->add_field('internalfield', XMLDB_TYPE_CHAR, '64', null, XMLDB_NOTNULL, null, null);
433         // Adding keys to table oauth2_user_field_mapping.
434         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
435         $table->add_key('issuerkey', XMLDB_KEY_FOREIGN, array('issuerid'), 'oauth2_issuer', array('id'));
436         $table->add_key('uniqinternal', XMLDB_KEY_UNIQUE, array('issuerid', 'internalfield'));
438         // Conditionally launch create table for oauth2_user_field_mapping.
439         if (!$dbman->table_exists($table)) {
440             $dbman->create_table($table);
441         }
443         // Main savepoint reached.
444         upgrade_main_savepoint(true, 2017040700.04);
445     }
447     if ($oldversion < 2017041801.00) {
449         // Define table course_completion_defaults to be created.
450         $table = new xmldb_table('course_completion_defaults');
452         // Adding fields to table course_completion_defaults.
453         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
454         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
455         $table->add_field('module', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
456         $table->add_field('completion', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
457         $table->add_field('completionview', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
458         $table->add_field('completionusegrade', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
459         $table->add_field('completionexpected', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
460         $table->add_field('customrules', XMLDB_TYPE_TEXT, null, null, null, null, null);
462         // Adding keys to table course_completion_defaults.
463         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
464         $table->add_key('module', XMLDB_KEY_FOREIGN, array('module'), 'modules', array('id'));
465         $table->add_key('course', XMLDB_KEY_FOREIGN, array('course'), 'course', array('id'));
467         // Adding indexes to table course_completion_defaults.
468         $table->add_index('coursemodule', XMLDB_INDEX_UNIQUE, array('course', 'module'));
470         // Conditionally launch create table for course_completion_defaults.
471         if (!$dbman->table_exists($table)) {
472             $dbman->create_table($table);
473         }
475         upgrade_main_savepoint(true, 2017041801.00);
476     }
478     if ($oldversion < 2017050500.01) {
479         // Get the list of parent event IDs.
480         $sql = "SELECT DISTINCT repeatid
481                            FROM {event}
482                           WHERE repeatid <> 0";
483         $parentids = array_keys($DB->get_records_sql($sql));
484         // Check if there are repeating events we need to process.
485         if (!empty($parentids)) {
486             // The repeat IDs of parent events should match their own ID.
487             // So we need to update parent events that have non-matching IDs and repeat IDs.
488             list($insql, $params) = $DB->get_in_or_equal($parentids);
489             $updatesql = "UPDATE {event}
490                              SET repeatid = id
491                            WHERE id <> repeatid
492                                  AND id $insql";
493             $DB->execute($updatesql, $params);
494         }
496         // Main savepoint reached.
497         upgrade_main_savepoint(true, 2017050500.01);
498     }
500     if ($oldversion < 2017050500.02) {
501         // MDL-58684:
502         // Remove all portfolio_tempdata records as these may contain serialized \file_system type objects, which are now unable to
503         // be unserialized because of changes to the file storage API made in MDL-46375. Portfolio now stores an id reference to
504         // files instead of the object.
505         // These records are normally removed after a successful export, however, can be left behind if the user abandons the
506         // export attempt (a stale record). Additionally, each stale record cannot be reused and is normally cleaned up by the cron
507         // task core\task\portfolio_cron_task. Since the cron task tries to unserialize them, and generates a warning, we'll remove
508         // all records here.
509         $DB->delete_records_select('portfolio_tempdata', 'id > ?', [0]);
511         // Main savepoint reached.
512         upgrade_main_savepoint(true, 2017050500.02);
513     }
515     if ($oldversion < 2017050900.01) {
516         // Create adhoc task for upgrading of existing calendar events.
517         $record = new \stdClass();
518         $record->classname = '\core\task\refresh_mod_calendar_events_task';
519         $record->component = 'core';
521         // Next run time based from nextruntime computation in \core\task\manager::queue_adhoc_task().
522         $nextruntime = time() - 1;
523         $record->nextruntime = $nextruntime;
524         $DB->insert_record('task_adhoc', $record);
526         // Main savepoint reached.
527         upgrade_main_savepoint(true, 2017050900.01);
528     }
530     // Automatically generated Moodle v3.3.0 release upgrade line.
531     // Put any upgrade step following this.
533     if ($oldversion < 2017061201.00) {
534         $table = new xmldb_table('course_sections');
535         $field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'availability');
537         // Define a field 'timemodified' in the 'course_sections' table.
538         if (!$dbman->field_exists($table, $field)) {
539             $dbman->add_field($table, $field);
540         }
542         upgrade_main_savepoint(true, 2017061201.00);
543     }
545     if ($oldversion < 2017061301.00) {
546         // Check if the value of 'navcourselimit' is set to the old default value, if so, change it to the new default.
547         if ($CFG->navcourselimit == 20) {
548             set_config('navcourselimit', 10);
549         }
551         // Main savepoint reached.
552         upgrade_main_savepoint(true, 2017061301.00);
553     }
555     if ($oldversion < 2017071000.00) {
557         // Define field requireconfirmation to be added to oauth2_issuer.
558         $table = new xmldb_table('oauth2_issuer');
559         $field = new xmldb_field('requireconfirmation', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1', 'sortorder');
561         // Conditionally launch add field requireconfirmation.
562         if (!$dbman->field_exists($table, $field)) {
563             $dbman->add_field($table, $field);
564         }
566         // Main savepoint reached.
567         upgrade_main_savepoint(true, 2017071000.00);
568     }
570     if ($oldversion < 2017071001.00) {
572         // Define field timemodified to be added to block_instances.
573         $table = new xmldb_table('block_instances');
574         $field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null,
575                 null, null, 'configdata');
577         // Conditionally launch add field timemodified.
578         if (!$dbman->field_exists($table, $field)) {
579             $dbman->add_field($table, $field);
581             // Set field to current time.
582             $DB->set_field('block_instances', 'timemodified', time());
584             // Changing nullability of field timemodified on table block_instances to not null.
585             $field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL,
586                     null, null, 'configdata');
588             // Launch change of nullability for field timemodified.
589             $dbman->change_field_notnull($table, $field);
591             // Define index timemodified (not unique) to be added to block_instances.
592             $index = new xmldb_index('timemodified', XMLDB_INDEX_NOTUNIQUE, array('timemodified'));
594             // Conditionally launch add index timemodified.
595             if (!$dbman->index_exists($table, $index)) {
596                 $dbman->add_index($table, $index);
597             }
598         }
600         // Define field timecreated to be added to block_instances.
601         $field = new xmldb_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null,
602                 null, null, 'configdata');
604         // Conditionally launch add field timecreated.
605         if (!$dbman->field_exists($table, $field)) {
606             $dbman->add_field($table, $field);
608             // Set field to current time.
609             $DB->set_field('block_instances', 'timecreated', time());
611             // Changing nullability of field timecreated on table block_instances to not null.
612             $field = new xmldb_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL,
613                     null, null, 'configdata');
615             // Launch change of nullability for field timecreated.
616             $dbman->change_field_notnull($table, $field);
617         }
619         // Main savepoint reached.
620         upgrade_main_savepoint(true, 2017071001.00);
621     }
623     if ($oldversion < 2017071100.00 ) {
624         // Clean old upgrade setting not used anymore.
625         unset_config('upgrade_minmaxgradestepignored');
626         upgrade_main_savepoint(true, 2017071100.00);
627     }
629     if ($oldversion < 2017072000.02) {
631         // Define table analytics_models to be created.
632         $table = new xmldb_table('analytics_models');
634         // Adding fields to table analytics_models.
635         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
636         $table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
637         $table->add_field('trained', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
638         $table->add_field('target', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
639         $table->add_field('indicators', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
640         $table->add_field('timesplitting', XMLDB_TYPE_CHAR, '255', null, null, null, null);
641         $table->add_field('version', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
642         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
643         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
644         $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
646         // Adding keys to table analytics_models.
647         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
649         // Adding indexes to table analytics_models.
650         $table->add_index('enabledandtrained', XMLDB_INDEX_NOTUNIQUE, array('enabled', 'trained'));
652         // Conditionally launch create table for analytics_models.
653         if (!$dbman->table_exists($table)) {
654             $dbman->create_table($table);
655         }
657         // Define table analytics_models_log to be created.
658         $table = new xmldb_table('analytics_models_log');
660         // Adding fields to table analytics_models_log.
661         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
662         $table->add_field('modelid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
663         $table->add_field('version', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
664         $table->add_field('target', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
665         $table->add_field('indicators', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
666         $table->add_field('timesplitting', XMLDB_TYPE_CHAR, '255', null, null, null, null);
667         $table->add_field('score', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, '0');
668         $table->add_field('info', XMLDB_TYPE_TEXT, null, null, null, null, null);
669         $table->add_field('dir', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
670         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
671         $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
673         // Adding keys to table analytics_models_log.
674         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
676         // Adding indexes to table analytics_models_log.
677         $table->add_index('modelid', XMLDB_INDEX_NOTUNIQUE, array('modelid'));
679         // Conditionally launch create table for analytics_models_log.
680         if (!$dbman->table_exists($table)) {
681             $dbman->create_table($table);
682         }
684         // Define table analytics_predictions to be created.
685         $table = new xmldb_table('analytics_predictions');
687         // Adding fields to table analytics_predictions.
688         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
689         $table->add_field('modelid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
690         $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
691         $table->add_field('sampleid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
692         $table->add_field('rangeindex', XMLDB_TYPE_INTEGER, '5', null, XMLDB_NOTNULL, null, null);
693         $table->add_field('prediction', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, null);
694         $table->add_field('predictionscore', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, null);
695         $table->add_field('calculations', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
696         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
698         // Adding keys to table analytics_predictions.
699         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
701         // Adding indexes to table analytics_predictions.
702         $table->add_index('modelidandcontextid', XMLDB_INDEX_NOTUNIQUE, array('modelid', 'contextid'));
704         // Conditionally launch create table for analytics_predictions.
705         if (!$dbman->table_exists($table)) {
706             $dbman->create_table($table);
707         }
709         // Define table analytics_train_samples to be created.
710         $table = new xmldb_table('analytics_train_samples');
712         // Adding fields to table analytics_train_samples.
713         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
714         $table->add_field('modelid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
715         $table->add_field('analysableid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
716         $table->add_field('timesplitting', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
717         $table->add_field('fileid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
718         $table->add_field('sampleids', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
719         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
721         // Adding keys to table analytics_train_samples.
722         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
724         // Adding indexes to table analytics_train_samples.
725         $table->add_index('modelidandanalysableidandtimesplitting', XMLDB_INDEX_NOTUNIQUE,
726             array('modelid', 'analysableid', 'timesplitting'));
728         // Conditionally launch create table for analytics_train_samples.
729         if (!$dbman->table_exists($table)) {
730             $dbman->create_table($table);
731         }
733         // Define table analytics_predict_ranges to be created.
734         $table = new xmldb_table('analytics_predict_ranges');
736         // Adding fields to table analytics_predict_ranges.
737         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
738         $table->add_field('modelid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
739         $table->add_field('analysableid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
740         $table->add_field('timesplitting', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
741         $table->add_field('rangeindex', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
742         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
744         // Adding keys to table analytics_predict_ranges.
745         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
747         // Adding indexes to table analytics_predict_ranges.
748         $table->add_index('modelidandanalysableidandtimesplitting', XMLDB_INDEX_NOTUNIQUE,
749             array('modelid', 'analysableid', 'timesplitting'));
751         // Conditionally launch create table for analytics_predict_ranges.
752         if (!$dbman->table_exists($table)) {
753             $dbman->create_table($table);
754         }
756         // Define table analytics_used_files to be created.
757         $table = new xmldb_table('analytics_used_files');
759         // Adding fields to table analytics_used_files.
760         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
761         $table->add_field('modelid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
762         $table->add_field('fileid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
763         $table->add_field('action', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, null, null);
764         $table->add_field('time', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
766         // Adding keys to table analytics_used_files.
767         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
769         // Adding indexes to table analytics_used_files.
770         $table->add_index('modelidandfileidandaction', XMLDB_INDEX_NOTUNIQUE, array('modelid', 'fileid', 'action'));
772         // Conditionally launch create table for analytics_used_files.
773         if (!$dbman->table_exists($table)) {
774             $dbman->create_table($table);
775         }
777         // Main savepoint reached.
778         upgrade_main_savepoint(true, 2017072000.02);
779     }
781     if ($oldversion < 2017072700.01) {
782         // Changing nullability of field email on table oauth2_system_account to null.
783         $table = new xmldb_table('oauth2_system_account');
784         $field = new xmldb_field('email', XMLDB_TYPE_TEXT, null, null, null, null, null, 'grantedscopes');
786         // Launch change of nullability for field email.
787         $dbman->change_field_notnull($table, $field);
789         // Main savepoint reached.
790         upgrade_main_savepoint(true, 2017072700.01);
791     }
793     if ($oldversion < 2017072700.02) {
795         // If the site was previously registered with http://hub.moodle.org change the registration to
796         // point to https://moodle.net - this is the correct hub address using https protocol.
797         $oldhuburl = "http://hub.moodle.org";
798         $newhuburl = "https://moodle.net";
799         $cleanoldhuburl = preg_replace('/[^A-Za-z0-9_-]/i', '', $oldhuburl);
800         $cleannewhuburl = preg_replace('/[^A-Za-z0-9_-]/i', '', $newhuburl);
802         // Update existing registration.
803         $DB->execute("UPDATE {registration_hubs} SET hubname = ?, huburl = ? WHERE huburl = ?",
804             ['Moodle.net', $newhuburl, $oldhuburl]);
806         // Update settings of existing registration.
807         $sqlnamelike = $DB->sql_like('name', '?');
808         $entries = $DB->get_records_sql("SELECT * FROM {config_plugins} where plugin=? and " . $sqlnamelike,
809             ['hub', '%' . $DB->sql_like_escape('_' . $cleanoldhuburl)]);
810         foreach ($entries as $entry) {
811             $newname = substr($entry->name, 0, -strlen($cleanoldhuburl)) . $cleannewhuburl;
812             try {
813                 $DB->update_record('config_plugins', ['id' => $entry->id, 'name' => $newname]);
814             } catch (dml_exception $e) {
815                 // Entry with new name already exists, remove the one with an old name.
816                 $DB->delete_records('config_plugins', ['id' => $entry->id]);
817             }
818         }
820         // Update published courses.
821         $DB->execute('UPDATE {course_published} SET huburl = ? WHERE huburl = ?', [$newhuburl, $oldhuburl]);
823         // Main savepoint reached.
824         upgrade_main_savepoint(true, 2017072700.02);
825     }
827     if ($oldversion < 2017080700.01) {
829         // Get the table by its previous name.
830         $table = new xmldb_table('analytics_predict_ranges');
831         if ($dbman->table_exists($table)) {
833             // We can only accept this because we are in master.
834             $DB->delete_records('analytics_predictions');
835             $DB->delete_records('analytics_used_files', array('action' => 'predicted'));
836             $DB->delete_records('analytics_predict_ranges');
838             // Define field sampleids to be added to analytics_predict_ranges (renamed below to analytics_predict_samples).
839             $field = new xmldb_field('sampleids', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null, 'rangeindex');
841             // Conditionally launch add field sampleids.
842             if (!$dbman->field_exists($table, $field)) {
843                 $dbman->add_field($table, $field);
844             }
846             // Define field timemodified to be added to analytics_predict_ranges (renamed below to analytics_predict_samples).
847             $field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'timecreated');
849             // Conditionally launch add field timemodified.
850             if (!$dbman->field_exists($table, $field)) {
851                 $dbman->add_field($table, $field);
852             }
854             // Rename the table to its new name.
855             $dbman->rename_table($table, 'analytics_predict_samples');
856         }
858         $table = new xmldb_table('analytics_predict_samples');
860         $index = new xmldb_index('modelidandanalysableidandtimesplitting', XMLDB_INDEX_NOTUNIQUE,
861             array('modelid', 'analysableid', 'timesplitting'));
863         // Conditionally launch drop index.
864         if ($dbman->index_exists($table, $index)) {
865             $dbman->drop_index($table, $index);
866         }
868         $index = new xmldb_index('modelidandanalysableidandtimesplittingandrangeindex', XMLDB_INDEX_NOTUNIQUE,
869             array('modelid', 'analysableid', 'timesplitting', 'rangeindex'));
871         // Conditionally launch add index.
872         if (!$dbman->index_exists($table, $index)) {
873             $dbman->add_index($table, $index);
874         }
876         // Main savepoint reached.
877         upgrade_main_savepoint(true, 2017080700.01);
878     }
880     if ($oldversion < 2017082200.00) {
881         $plugins = ['radius', 'fc', 'nntp', 'pam', 'pop3', 'imap'];
883         foreach ($plugins as $plugin) {
884             // Check to see if the plugin exists on disk.
885             // If it does not, remove the config for it.
886             if (!file_exists($CFG->dirroot . "/auth/{$plugin}/auth.php")) {
887                 // Clean config.
888                 unset_all_config_for_plugin("auth_{$plugin}");
889             }
890         }
891         upgrade_main_savepoint(true, 2017082200.00);
892     }
894     if ($oldversion < 2017082200.01) {
896         // Define table analytics_indicator_calc to be created.
897         $table = new xmldb_table('analytics_indicator_calc');
899         // Adding fields to table analytics_indicator_calc.
900         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
901         $table->add_field('starttime', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
902         $table->add_field('endtime', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
903         $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
904         $table->add_field('sampleorigin', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
905         $table->add_field('sampleid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
906         $table->add_field('indicator', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
907         $table->add_field('value', XMLDB_TYPE_NUMBER, '10, 2', null, null, null, null);
908         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
910         // Adding keys to table analytics_indicator_calc.
911         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
913         // Adding indexes to table analytics_indicator_calc.
914         $table->add_index('starttime-endtime-contextid', XMLDB_INDEX_NOTUNIQUE, array('starttime', 'endtime', 'contextid'));
916         // Conditionally launch create table for analytics_indicator_calc.
917         if (!$dbman->table_exists($table)) {
918             $dbman->create_table($table);
919         }
921         // Main savepoint reached.
922         upgrade_main_savepoint(true, 2017082200.01);
923     }
925     if ($oldversion < 2017082300.01) {
927         // This script in included in each major version upgrade process so make sure we don't run it twice.
928         if (empty($CFG->linkcoursesectionsupgradescriptwasrun)) {
929             // Check if the site is using a boost-based theme.
930             // If value of 'linkcoursesections' is set to the old default value, change it to the new default.
931             if (upgrade_theme_is_from_family('boost', $CFG->theme)) {
932                 set_config('linkcoursesections', 1);
933             }
934             set_config('linkcoursesectionsupgradescriptwasrun', 1);
935         }
937         // Main savepoint reached.
938         upgrade_main_savepoint(true, 2017082300.01);
939     }
941     if ($oldversion < 2017082500.00) {
942         // Handle FKs for the table 'analytics_models_log'.
943         $table = new xmldb_table('analytics_models_log');
945         // Remove the existing index before adding FK (which creates an index).
946         $index = new xmldb_index('modelid', XMLDB_INDEX_NOTUNIQUE, array('modelid'));
948         // Conditionally launch drop index.
949         if ($dbman->index_exists($table, $index)) {
950             $dbman->drop_index($table, $index);
951         }
953         // Now, add the FK.
954         $key = new xmldb_key('modelid', XMLDB_KEY_FOREIGN, array('modelid'), 'analytics_models', array('id'));
955         $dbman->add_key($table, $key);
957         // Handle FKs for the table 'analytics_predictions'.
958         $table = new xmldb_table('analytics_predictions');
959         $key = new xmldb_key('modelid', XMLDB_KEY_FOREIGN, array('modelid'), 'analytics_models', array('id'));
960         $dbman->add_key($table, $key);
962         $key = new xmldb_key('contextid', XMLDB_KEY_FOREIGN, array('contextid'), 'context', array('id'));
963         $dbman->add_key($table, $key);
965         // Handle FKs for the table 'analytics_train_samples'.
966         $table = new xmldb_table('analytics_train_samples');
967         $key = new xmldb_key('modelid', XMLDB_KEY_FOREIGN, array('modelid'), 'analytics_models', array('id'));
968         $dbman->add_key($table, $key);
970         $key = new xmldb_key('fileid', XMLDB_KEY_FOREIGN, array('fileid'), 'files', array('id'));
971         $dbman->add_key($table, $key);
973         // Handle FKs for the table 'analytics_predict_samples'.
974         $table = new xmldb_table('analytics_predict_samples');
975         $key = new xmldb_key('modelid', XMLDB_KEY_FOREIGN, array('modelid'), 'analytics_models', array('id'));
976         $dbman->add_key($table, $key);
978         // Handle FKs for the table 'analytics_used_files'.
979         $table = new xmldb_table('analytics_used_files');
980         $key = new xmldb_key('modelid', XMLDB_KEY_FOREIGN, array('modelid'), 'analytics_models', array('id'));
981         $dbman->add_key($table, $key);
983         $key = new xmldb_key('fileid', XMLDB_KEY_FOREIGN, array('fileid'), 'files', array('id'));
984         $dbman->add_key($table, $key);
986         // Handle FKs for the table 'analytics_indicator_calc'.
987         $table = new xmldb_table('analytics_indicator_calc');
988         $key = new xmldb_key('contextid', XMLDB_KEY_FOREIGN, array('contextid'), 'context', array('id'));
989         $dbman->add_key($table, $key);
991         // Main savepoint reached.
992         upgrade_main_savepoint(true, 2017082500.00);
993     }
995     if ($oldversion < 2017082800.00) {
997         // Changing type of field prediction on table analytics_predictions to number.
998         $table = new xmldb_table('analytics_predictions');
999         $field = new xmldb_field('prediction', XMLDB_TYPE_NUMBER, '10, 2', null, XMLDB_NOTNULL, null, null, 'rangeindex');
1001         // Launch change of type for field prediction.
1002         $dbman->change_field_type($table, $field);
1004         // Main savepoint reached.
1005         upgrade_main_savepoint(true, 2017082800.00);
1006     }
1008     if ($oldversion < 2017090700.01) {
1010         // Define table analytics_prediction_actions to be created.
1011         $table = new xmldb_table('analytics_prediction_actions');
1013         // Adding fields to table analytics_prediction_actions.
1014         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1015         $table->add_field('predictionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1016         $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1017         $table->add_field('actionname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1018         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1020         // Adding keys to table analytics_prediction_actions.
1021         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1022         $table->add_key('predictionid', XMLDB_KEY_FOREIGN, array('predictionid'), 'analytics_predictions', array('id'));
1023         $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
1025         // Adding indexes to table analytics_prediction_actions.
1026         $table->add_index('predictionidanduseridandactionname', XMLDB_INDEX_NOTUNIQUE,
1027             array('predictionid', 'userid', 'actionname'));
1029         // Conditionally launch create table for analytics_prediction_actions.
1030         if (!$dbman->table_exists($table)) {
1031             $dbman->create_table($table);
1032         }
1034         // Main savepoint reached.
1035         upgrade_main_savepoint(true, 2017090700.01);
1036     }
1038     if ($oldversion < 2017091200.00) {
1039         // Force all messages to be reindexed.
1040         set_config('core_message_message_sent_lastindexrun', '0', 'core_search');
1041         set_config('core_message_message_received_lastindexrun', '0', 'core_search');
1043         // Main savepoint reached.
1044         upgrade_main_savepoint(true, 2017091200.00);
1045     }
1047     if ($oldversion < 2017091201.00) {
1048         // Define field userid to be added to task_adhoc.
1049         $table = new xmldb_table('task_adhoc');
1050         $field = new xmldb_field('userid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'customdata');
1052         // Conditionally launch add field userid.
1053         if (!$dbman->field_exists($table, $field)) {
1054             $dbman->add_field($table, $field);
1055         }
1057         $key = new xmldb_key('useriduser', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
1059         // Launch add key userid_user.
1060         $dbman->add_key($table, $key);
1062         // Main savepoint reached.
1063         upgrade_main_savepoint(true, 2017091201.00);
1064     }
1066     if ($oldversion < 2017092201.00) {
1068         // Remove duplicate registrations.
1069         $newhuburl = "https://moodle.net";
1070         $registrations = $DB->get_records('registration_hubs', ['huburl' => $newhuburl], 'confirmed DESC, id ASC');
1071         if (count($registrations) > 1) {
1072             $reg = array_shift($registrations);
1073             $DB->delete_records_select('registration_hubs', 'huburl = ? AND id <> ?', [$newhuburl, $reg->id]);
1074         }
1076         // Main savepoint reached.
1077         upgrade_main_savepoint(true, 2017092201.00);
1078     }
1080     if ($oldversion < 2017092202.00) {
1082         if (!file_exists($CFG->dirroot . '/blocks/messages/block_messages.php')) {
1084             // Delete instances.
1085             $instances = $DB->get_records_list('block_instances', 'blockname', ['messages']);
1086             $instanceids = array_keys($instances);
1088             if (!empty($instanceids)) {
1089                 $DB->delete_records_list('block_positions', 'blockinstanceid', $instanceids);
1090                 $DB->delete_records_list('block_instances', 'id', $instanceids);
1091                 list($sql, $params) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED);
1092                 $params['contextlevel'] = CONTEXT_BLOCK;
1093                 $DB->delete_records_select('context', "contextlevel=:contextlevel AND instanceid " . $sql, $params);
1095                 $preferences = array();
1096                 foreach ($instances as $instanceid => $instance) {
1097                     $preferences[] = 'block' . $instanceid . 'hidden';
1098                     $preferences[] = 'docked_block_instance_' . $instanceid;
1099                 }
1100                 $DB->delete_records_list('user_preferences', 'name', $preferences);
1101             }
1103             // Delete the block from the block table.
1104             $DB->delete_records('block', array('name' => 'messages'));
1106             // Remove capabilities.
1107             capabilities_cleanup('block_messages');
1109             // Clean config.
1110             unset_all_config_for_plugin('block_messages');
1111         }
1113         // Main savepoint reached.
1114         upgrade_main_savepoint(true, 2017092202.00);
1115     }
1117     if ($oldversion < 2017092700.00) {
1119         // Rename several fields in registration data to match the names of the properties that are sent to moodle.net.
1120         $renames = [
1121             'site_address_httpsmoodlenet' => 'site_street_httpsmoodlenet',
1122             'site_region_httpsmoodlenet' => 'site_regioncode_httpsmoodlenet',
1123             'site_country_httpsmoodlenet' => 'site_countrycode_httpsmoodlenet'];
1124         foreach ($renames as $oldparamname => $newparamname) {
1125             try {
1126                 $DB->execute("UPDATE {config_plugins} SET name = ? WHERE name = ? AND plugin = ?",
1127                     [$newparamname, $oldparamname, 'hub']);
1128             } catch (dml_exception $e) {
1129                 // Exception can happen if the config value with the new name already exists, ignore it and move on.
1130             }
1131         }
1133         // Main savepoint reached.
1134         upgrade_main_savepoint(true, 2017092700.00);
1135     }
1137     if ($oldversion < 2017092900.00) {
1138         // Define field categoryid to be added to event.
1139         $table = new xmldb_table('event');
1140         $field = new xmldb_field('categoryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'format');
1142         // Conditionally launch add field categoryid.
1143         if (!$dbman->field_exists($table, $field)) {
1144             $dbman->add_field($table, $field);
1145         }
1147         // Add the categoryid key.
1148         $key = new xmldb_key('categoryid', XMLDB_KEY_FOREIGN, array('categoryid'), 'course_categories', array('id'));
1149         $dbman->add_key($table, $key);
1151         // Add a new index for groupid/courseid/categoryid/visible/userid.
1152         // Do this before we remove the old index.
1153         $index = new xmldb_index('groupid-courseid-categoryid-visible-userid', XMLDB_INDEX_NOTUNIQUE, array('groupid', 'courseid', 'categoryid', 'visible', 'userid'));
1154         if (!$dbman->index_exists($table, $index)) {
1155             $dbman->add_index($table, $index);
1156         }
1158         // Drop the old index.
1159         $index = new xmldb_index('groupid-courseid-visible-userid', XMLDB_INDEX_NOTUNIQUE, array('groupid', 'courseid', 'visible', 'userid'));
1160         if ($dbman->index_exists($table, $index)) {
1161             $dbman->drop_index($table, $index);
1162         }
1164         // Main savepoint reached.
1165         upgrade_main_savepoint(true, 2017092900.00);
1166     }
1168     if ($oldversion < 2017100900.00) {
1169         // Add index on time modified to grade_outcomes_history, grade_categories_history,
1170         // grade_items_history, and scale_history.
1171         $table = new xmldb_table('grade_outcomes_history');
1172         $index = new xmldb_index('timemodified', XMLDB_INDEX_NOTUNIQUE, array('timemodified'));
1174         if (!$dbman->index_exists($table, $index)) {
1175             $dbman->add_index($table, $index);
1176         }
1178         $table = new xmldb_table('grade_items_history');
1179         $index = new xmldb_index('timemodified', XMLDB_INDEX_NOTUNIQUE, array('timemodified'));
1181         if (!$dbman->index_exists($table, $index)) {
1182             $dbman->add_index($table, $index);
1183         }
1185         $table = new xmldb_table('grade_categories_history');
1186         $index = new xmldb_index('timemodified', XMLDB_INDEX_NOTUNIQUE, array('timemodified'));
1188         if (!$dbman->index_exists($table, $index)) {
1189             $dbman->add_index($table, $index);
1190         }
1192         $table = new xmldb_table('scale_history');
1193         $index = new xmldb_index('timemodified', XMLDB_INDEX_NOTUNIQUE, array('timemodified'));
1195         if (!$dbman->index_exists($table, $index)) {
1196             $dbman->add_index($table, $index);
1197         }
1199         // Main savepoint reached.
1200         upgrade_main_savepoint(true, 2017100900.00);
1201     }
1203     if ($oldversion < 2017101000.00) {
1205         // Define table analytics_used_analysables to be created.
1206         $table = new xmldb_table('analytics_used_analysables');
1208         // Adding fields to table analytics_used_analysables.
1209         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1210         $table->add_field('modelid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1211         $table->add_field('action', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, null, null);
1212         $table->add_field('analysableid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1213         $table->add_field('timeanalysed', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1215         // Adding keys to table analytics_used_analysables.
1216         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1217         $table->add_key('modelid', XMLDB_KEY_FOREIGN, array('modelid'), 'analytics_models', array('id'));
1219         // Adding indexes to table analytics_used_analysables.
1220         $table->add_index('modelid-action', XMLDB_INDEX_NOTUNIQUE, array('modelid', 'action'));
1222         // Conditionally launch create table for analytics_used_analysables.
1223         if (!$dbman->table_exists($table)) {
1224             $dbman->create_table($table);
1225         }
1227         // Main savepoint reached.
1228         upgrade_main_savepoint(true, 2017101000.00);
1229     }
1231     if ($oldversion < 2017101000.01) {
1232         // Define field override to be added to course_modules_completion.
1233         $table = new xmldb_table('course_modules_completion');
1234         $field = new xmldb_field('overrideby', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'viewed');
1236         // Conditionally launch add field override.
1237         if (!$dbman->field_exists($table, $field)) {
1238             $dbman->add_field($table, $field);
1239         }
1241         // Main savepoint reached.
1242         upgrade_main_savepoint(true, 2017101000.01);
1243     }
1245     if ($oldversion < 2017101000.02) {
1246         // Define field 'timestart' to be added to 'analytics_predictions'.
1247         $table = new xmldb_table('analytics_predictions');
1248         $field = new xmldb_field('timestart', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'timecreated');
1250         // Conditionally launch add field 'timestart'.
1251         if (!$dbman->field_exists($table, $field)) {
1252             $dbman->add_field($table, $field);
1253         }
1255         // Define field 'timeend' to be added to 'analytics_predictions'.
1256         $field = new xmldb_field('timeend', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'timestart');
1258         // Conditionally launch add field 'timeend'.
1259         if (!$dbman->field_exists($table, $field)) {
1260             $dbman->add_field($table, $field);
1261         }
1263         // Main savepoint reached.
1264         upgrade_main_savepoint(true, 2017101000.02);
1265     }
1267     if ($oldversion < 2017101200.00) {
1268         // Define table search_index_requests to be created.
1269         $table = new xmldb_table('search_index_requests');
1271         // Adding fields to table search_index_requests.
1272         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1273         $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1274         $table->add_field('searcharea', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1275         $table->add_field('timerequested', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1276         $table->add_field('partialarea', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
1277         $table->add_field('partialtime', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1279         // Adding keys to table search_index_requests.
1280         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1281         $table->add_key('contextid', XMLDB_KEY_FOREIGN, array('contextid'), 'context', array('id'));
1283         // Conditionally launch create table for search_index_requests.
1284         if (!$dbman->table_exists($table)) {
1285             $dbman->create_table($table);
1286         }
1288         // Main savepoint reached.
1289         upgrade_main_savepoint(true, 2017101200.00);
1290     }
1292     // Index modification upgrade step.
1293     if ($oldversion < 2017101300.01) {
1295         $table = new xmldb_table('analytics_used_files');
1297         // Define index modelidandfileidandaction (not unique) to be dropped form analytics_used_files.
1298         $index = new xmldb_index('modelidandfileidandaction', XMLDB_INDEX_NOTUNIQUE, array('modelid', 'fileid', 'action'));
1300         // Conditionally launch drop index modelidandfileidandaction.
1301         if ($dbman->index_exists($table, $index)) {
1302             $dbman->drop_index($table, $index);
1303         }
1305         // Define index modelidandactionandfileid (not unique) to be dropped form analytics_used_files.
1306         $index = new xmldb_index('modelidandactionandfileid', XMLDB_INDEX_NOTUNIQUE, array('modelid', 'action', 'fileid'));
1308         // Conditionally launch add index modelidandactionandfileid.
1309         if (!$dbman->index_exists($table, $index)) {
1310             $dbman->add_index($table, $index);
1311         }
1313         // Main savepoint reached.
1314         upgrade_main_savepoint(true, 2017101300.01);
1315     }
1317     if ($oldversion < 2017101900.01) {
1319         $fs = get_file_storage();
1320         $models = $DB->get_records('analytics_models');
1321         foreach ($models as $model) {
1322             $files = $fs->get_directory_files(\context_system::instance()->id, 'analytics', 'unlabelled', $model->id,
1323                 '/analysable/', true, true);
1324             foreach ($files as $file) {
1325                 $file->delete();
1326             }
1327         }
1329         // Main savepoint reached.
1330         upgrade_main_savepoint(true, 2017101900.01);
1331     }
1333     if ($oldversion < 2017101900.02) {
1334         // Create adhoc task for upgrading of existing calendar events.
1335         $record = new \stdClass();
1336         $record->classname = '\core\task\refresh_mod_calendar_events_task';
1337         $record->component = 'core';
1339         // Next run time based from nextruntime computation in \core\task\manager::queue_adhoc_task().
1340         $nextruntime = time() - 1;
1341         $record->nextruntime = $nextruntime;
1342         $DB->insert_record('task_adhoc', $record);
1344         // Main savepoint reached.
1345         upgrade_main_savepoint(true, 2017101900.02);
1346     }
1348     if ($oldversion < 2017102100.01) {
1349         // We will need to force them onto ssl if loginhttps is set.
1350         if (!empty($CFG->loginhttps)) {
1351             set_config('overridetossl', 1);
1352         }
1353         // Loginhttps should no longer be set.
1354         unset_config('loginhttps');
1356         // Main savepoint reached.
1357         upgrade_main_savepoint(true, 2017102100.01);
1358     }
1360     if ($oldversion < 2017110300.01) {
1362         // Define field categoryid to be added to event_subscriptions.
1363         $table = new xmldb_table('event_subscriptions');
1364         $field = new xmldb_field('categoryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'url');
1366         // Conditionally launch add field categoryid.
1367         if (!$dbman->field_exists($table, $field)) {
1368             $dbman->add_field($table, $field);
1369         }
1371         // Main savepoint reached.
1372         upgrade_main_savepoint(true, 2017110300.01);
1373     }
1375     // Automatically generated Moodle v3.4.0 release upgrade line.
1376     // Put any upgrade step following this.
1378     if ($oldversion < 2017111300.02) {
1380         // Define field basicauth to be added to oauth2_issuer.
1381         $table = new xmldb_table('oauth2_issuer');
1382         $field = new xmldb_field('basicauth', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'showonloginpage');
1384         // Conditionally launch add field basicauth.
1385         if (!$dbman->field_exists($table, $field)) {
1386             $dbman->add_field($table, $field);
1387         }
1389         // Main savepoint reached.
1390         upgrade_main_savepoint(true, 2017111300.02);
1391     }
1393     if ($oldversion < 2017121200.00) {
1395         // Define key subscriptionid (foreign) to be added to event.
1396         $table = new xmldb_table('event');
1397         $key = new xmldb_key('subscriptionid', XMLDB_KEY_FOREIGN, array('subscriptionid'), 'event_subscriptions', array('id'));
1399         // Launch add key subscriptionid.
1400         $dbman->add_key($table, $key);
1402         // Define index uuid (not unique) to be added to event.
1403         $table = new xmldb_table('event');
1404         $index = new xmldb_index('uuid', XMLDB_INDEX_NOTUNIQUE, array('uuid'));
1406         // Conditionally launch add index uuid.
1407         if (!$dbman->index_exists($table, $index)) {
1408             $dbman->add_index($table, $index);
1409         }
1411         // Main savepoint reached.
1412         upgrade_main_savepoint(true, 2017121200.00);
1413     }
1415     if ($oldversion < 2017121900.00) {
1417         // Define table role_allow_view to be created.
1418         $table = new xmldb_table('role_allow_view');
1420         // Adding fields to table role_allow_view.
1421         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1422         $table->add_field('roleid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1423         $table->add_field('allowview', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1425         // Adding keys to table role_allow_view.
1426         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1427         $table->add_key('roleid', XMLDB_KEY_FOREIGN, array('roleid'), 'role', array('id'));
1428         $table->add_key('allowview', XMLDB_KEY_FOREIGN, array('allowview'), 'role', array('id'));
1430         // Conditionally launch create table for role_allow_view.
1431         if (!$dbman->table_exists($table)) {
1432             $dbman->create_table($table);
1433         }
1435         $index = new xmldb_index('roleid-allowview', XMLDB_INDEX_UNIQUE, array('roleid', 'allowview'));
1437         // Conditionally launch add index roleid.
1438         if (!$dbman->index_exists($table, $index)) {
1439             $dbman->add_index($table, $index);
1440         }
1442         $roles = $DB->get_records('role', array(), 'sortorder ASC');
1444         $DB->delete_records('role_allow_view');
1445         foreach ($roles as $role) {
1446             foreach ($roles as $allowedrole) {
1447                 $record = new stdClass();
1448                 $record->roleid      = $role->id;
1449                 $record->allowview = $allowedrole->id;
1450                 $DB->insert_record('role_allow_view', $record);
1451             }
1452         }
1454         // Main savepoint reached.
1455         upgrade_main_savepoint(true, 2017121900.00);
1456     }
1458     if ($oldversion < 2017122200.01) {
1460         // Define field indexpriority to be added to search_index_requests. Allow null initially.
1461         $table = new xmldb_table('search_index_requests');
1462         $field = new xmldb_field('indexpriority', XMLDB_TYPE_INTEGER, '10',
1463                 null, null, null, null, 'partialtime');
1465         // Conditionally add field.
1466         if (!$dbman->field_exists($table, $field)) {
1467             $dbman->add_field($table, $field);
1469             // Set existing values to 'normal' value (100).
1470             $DB->set_field('search_index_requests', 'indexpriority', 100);
1472             // Now make the field 'NOT NULL'.
1473             $field = new xmldb_field('indexpriority', XMLDB_TYPE_INTEGER, '10',
1474                     null, XMLDB_NOTNULL, null, null, 'partialtime');
1475             $dbman->change_field_notnull($table, $field);
1476         }
1478         // Define index indexprioritytimerequested (not unique) to be added to search_index_requests.
1479         $index = new xmldb_index('indexprioritytimerequested', XMLDB_INDEX_NOTUNIQUE,
1480                 array('indexpriority', 'timerequested'));
1482         // Conditionally launch add index indexprioritytimerequested.
1483         if (!$dbman->index_exists($table, $index)) {
1484             $dbman->add_index($table, $index);
1485         }
1487         // Main savepoint reached.
1488         upgrade_main_savepoint(true, 2017122200.01);
1489     }
1491     if ($oldversion < 2018020500.00) {
1493         $topcategory = new stdClass();
1494         $topcategory->name = 'top'; // A non-real name for the top category. It will be localised at the display time.
1495         $topcategory->info = '';
1496         $topcategory->parent = 0;
1497         $topcategory->sortorder = 0;
1499         // Get the total record count - used for the progress bar.
1500         $total = $DB->count_records_sql("SELECT COUNT(DISTINCT contextid) FROM {question_categories} WHERE parent = 0");
1502         // Get the records themselves - a list of contextids.
1503         $rs = $DB->get_recordset_sql("SELECT DISTINCT contextid FROM {question_categories} WHERE parent = 0");
1505         // For each context, create a single top-level category.
1506         $i = 0;
1507         $pbar = new progress_bar('createtopquestioncategories', 500, true);
1508         foreach ($rs as $contextid => $notused) {
1509             $topcategory->contextid = $contextid;
1510             $topcategory->stamp = make_unique_id_code();
1512             $topcategoryid = $DB->insert_record('question_categories', $topcategory);
1514             $DB->set_field_select('question_categories', 'parent', $topcategoryid,
1515                     'contextid = ? AND id <> ? AND parent = 0',
1516                     array($contextid, $topcategoryid));
1518             // Update progress.
1519             $i++;
1520             $pbar->update($i, $total, "Creating top-level question categories - $i/$total.");
1521         }
1523         $rs->close();
1525         // Main savepoint reached.
1526         upgrade_main_savepoint(true, 2018020500.00);
1527     }
1529     if ($oldversion < 2018022800.01) {
1530         // Fix old block configurations that use the deprecated (and now removed) object class.
1531         upgrade_fix_block_instance_configuration();
1533         // Main savepoint reached.
1534         upgrade_main_savepoint(true, 2018022800.01);
1535     }
1537     if ($oldversion < 2018022800.02) {
1538         // Define index taggeditem (unique) to be dropped form tag_instance.
1539         $table = new xmldb_table('tag_instance');
1540         $index = new xmldb_index('taggeditem', XMLDB_INDEX_UNIQUE, array('component',
1541             'itemtype', 'itemid', 'tiuserid', 'tagid'));
1543         // Conditionally launch drop index taggeditem.
1544         if ($dbman->index_exists($table, $index)) {
1545             $dbman->drop_index($table, $index);
1546         }
1548         $index = new xmldb_index('taggeditem', XMLDB_INDEX_UNIQUE, array('component',
1549             'itemtype', 'itemid', 'contextid', 'tiuserid', 'tagid'));
1551         // Conditionally launch add index taggeditem.
1552         if (!$dbman->index_exists($table, $index)) {
1553             $dbman->add_index($table, $index);
1554         }
1556         // Main savepoint reached.
1557         upgrade_main_savepoint(true, 2018022800.02);
1558     }
1560     if ($oldversion < 2018022800.03) {
1562         // Define field multiplecontexts to be added to tag_area.
1563         $table = new xmldb_table('tag_area');
1564         $field = new xmldb_field('multiplecontexts', XMLDB_TYPE_INTEGER, '1', null,
1565             XMLDB_NOTNULL, null, '0', 'showstandard');
1567         // Conditionally launch add field multiplecontexts.
1568         if (!$dbman->field_exists($table, $field)) {
1569             $dbman->add_field($table, $field);
1570         }
1572         // Main savepoint reached.
1573         upgrade_main_savepoint(true, 2018022800.03);
1574     }
1576     if ($oldversion < 2018032200.01) {
1577         // Define table 'messages' to be created.
1578         $table = new xmldb_table('messages');
1580         // Adding fields to table 'messages'.
1581         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1582         $table->add_field('useridfrom', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1583         $table->add_field('conversationid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1584         $table->add_field('subject', XMLDB_TYPE_TEXT, null, null, null, null, null);
1585         $table->add_field('fullmessage', XMLDB_TYPE_TEXT, null, null, null, null, null);
1586         $table->add_field('fullmessageformat', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, 0);
1587         $table->add_field('fullmessagehtml', XMLDB_TYPE_TEXT, null, null, null, null, null);
1588         $table->add_field('smallmessage', XMLDB_TYPE_TEXT, null, null, null, null, null);
1589         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1591         // Adding keys to table 'messages'.
1592         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1593         $table->add_key('useridfrom', XMLDB_KEY_FOREIGN, array('useridfrom'), 'user', array('id'));
1594         $table->add_key('conversationid', XMLDB_KEY_FOREIGN, array('conversationid'), 'message_conversations', array('id'));
1596         // Conditionally launch create table for 'messages'.
1597         if (!$dbman->table_exists($table)) {
1598             $dbman->create_table($table);
1599         }
1601         // Define table 'message_conversations' to be created.
1602         $table = new xmldb_table('message_conversations');
1604         // Adding fields to table 'message_conversations'.
1605         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1606         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1608         // Adding keys to table 'message_conversations'.
1609         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1611         // Conditionally launch create table for 'message_conversations'.
1612         if (!$dbman->table_exists($table)) {
1613             $dbman->create_table($table);
1614         }
1616         // Define table 'message_conversation_members' to be created.
1617         $table = new xmldb_table('message_conversation_members');
1619         // Adding fields to table 'message_conversation_members'.
1620         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1621         $table->add_field('conversationid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1622         $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1623         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1625         // Adding keys to table 'message_conversation_members'.
1626         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1627         $table->add_key('conversationid', XMLDB_KEY_FOREIGN, array('conversationid'), 'message_conversations', array('id'));
1628         $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
1630         // Conditionally launch create table for 'message_conversation_members'.
1631         if (!$dbman->table_exists($table)) {
1632             $dbman->create_table($table);
1633         }
1635         // Define table 'message_user_actions' to be created.
1636         $table = new xmldb_table('message_user_actions');
1638         // Adding fields to table 'message_user_actions'.
1639         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1640         $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1641         $table->add_field('messageid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1642         $table->add_field('action', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1643         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1645         // Adding keys to table 'message_user_actions'.
1646         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1647         $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
1648         $table->add_key('messageid', XMLDB_KEY_FOREIGN, array('messageid'), 'messages', array('id'));
1650         // Conditionally launch create table for 'message_user_actions'.
1651         if (!$dbman->table_exists($table)) {
1652             $dbman->create_table($table);
1653         }
1655         // Define table 'notifications' to be created.
1656         $table = new xmldb_table('notifications');
1658         // Adding fields to table 'notifications'.
1659         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1660         $table->add_field('useridfrom', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1661         $table->add_field('useridto', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1662         $table->add_field('subject', XMLDB_TYPE_TEXT, null, null, null, null, null);
1663         $table->add_field('fullmessage', XMLDB_TYPE_TEXT, null, null, null, null, null);
1664         $table->add_field('fullmessageformat', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, 0);
1665         $table->add_field('fullmessagehtml', XMLDB_TYPE_TEXT, null, null, null, null, null);
1666         $table->add_field('smallmessage', XMLDB_TYPE_TEXT, null, null, null, null, null);
1667         $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null);
1668         $table->add_field('eventtype', XMLDB_TYPE_CHAR, '100', null, null, null, null);
1669         $table->add_field('contexturl', XMLDB_TYPE_TEXT, null, null, null, null, null);
1670         $table->add_field('contexturlname', XMLDB_TYPE_TEXT, null, null, null, null, null);
1671         $table->add_field('timeread', XMLDB_TYPE_INTEGER, '10', null, false, null, null);
1672         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1674         // Adding keys to table 'notifications'.
1675         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1676         $table->add_key('useridto', XMLDB_KEY_FOREIGN, array('useridto'), 'user', array('id'));
1678         // Conditionally launch create table for 'notifications'.
1679         if (!$dbman->table_exists($table)) {
1680             $dbman->create_table($table);
1681         }
1683         // Main savepoint reached.
1684         upgrade_main_savepoint(true, 2018032200.01);
1685     }
1687     if ($oldversion < 2018032200.04) {
1688         // Define table 'message_conversations' to be updated.
1689         $table = new xmldb_table('message_conversations');
1690         $field = new xmldb_field('convhash', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null, 'id');
1692         // Conditionally launch add field 'convhash'.
1693         if (!$dbman->field_exists($table, $field)) {
1694             $dbman->add_field($table, $field);
1695         }
1697         // Conditionally launch add index.
1698         $index = new xmldb_index('convhash', XMLDB_INDEX_UNIQUE, array('convhash'));
1699         if (!$dbman->index_exists($table, $index)) {
1700             $dbman->add_index($table, $index);
1701         }
1703         // Main savepoint reached.
1704         upgrade_main_savepoint(true, 2018032200.04);
1705     }
1707     if ($oldversion < 2018032200.05) {
1708         // Drop table that is no longer needed.
1709         $table = new xmldb_table('message_working');
1710         if ($dbman->table_exists($table)) {
1711             $dbman->drop_table($table);
1712         }
1714         // Main savepoint reached.
1715         upgrade_main_savepoint(true, 2018032200.05);
1716     }
1718     if ($oldversion < 2018032200.06) {
1719         // Define table 'message_user_actions' to add an index to.
1720         $table = new xmldb_table('message_user_actions');
1722         // Conditionally launch add index.
1723         $index = new xmldb_index('userid_messageid_action', XMLDB_INDEX_UNIQUE, array('userid', 'messageid', 'action'));
1724         if (!$dbman->index_exists($table, $index)) {
1725             $dbman->add_index($table, $index);
1726         }
1728         // Main savepoint reached.
1729         upgrade_main_savepoint(true, 2018032200.06);
1730     }
1732     if ($oldversion < 2018032200.07) {
1733         // Define table 'messages' to add an index to.
1734         $table = new xmldb_table('messages');
1736         // Conditionally launch add index.
1737         $index = new xmldb_index('conversationid_timecreated', XMLDB_INDEX_NOTUNIQUE, array('conversationid', 'timecreated'));
1738         if (!$dbman->index_exists($table, $index)) {
1739             $dbman->add_index($table, $index);
1740         }
1742         // Main savepoint reached.
1743         upgrade_main_savepoint(true, 2018032200.07);
1744     }
1746     if ($oldversion < 2018032700.00) {
1747         // Update default search engine to search_simpledb if global search is disabled and there is no solr index defined.
1748         if (empty($CFG->enableglobalsearch) && empty(get_config('search_solr', 'indexname'))) {
1749             set_config('searchengine', 'simpledb');
1750         }
1752         // Main savepoint reached.
1753         upgrade_main_savepoint(true, 2018032700.00);
1754     }
1756     if ($oldversion < 2018040500.01) {
1758         // Define field cohort to be added to theme. Allow null initially.
1759         $table = new xmldb_table('cohort');
1760         $field = new xmldb_field('theme', XMLDB_TYPE_CHAR, '50',
1761                 null, null, null, null, 'timemodified');
1763         // Conditionally add field.
1764         if (!$dbman->field_exists($table, $field)) {
1765             $dbman->add_field($table, $field);
1766         }
1768         // Main savepoint reached.
1769         upgrade_main_savepoint(true, 2018040500.01);
1770     }
1772     if ($oldversion < 2018050900.01) {
1773         // Update default digital age consent map according to the current legislation on each country.
1774         $ageofdigitalconsentmap = implode(PHP_EOL, [
1775             '*, 16',
1776             'AT, 14',
1777             'ES, 14',
1778             'US, 13'
1779         ]);
1780         set_config('agedigitalconsentmap', $ageofdigitalconsentmap);
1782         // Main savepoint reached.
1783         upgrade_main_savepoint(true, 2018050900.01);
1784     }
1786     // Automatically generated Moodle v3.5.0 release upgrade line.
1787     // Put any upgrade step following this.
1789     if ($oldversion < 2018062800.01) {
1790         // Add foreign key fk_user to the comments table.
1791         $table = new xmldb_table('comments');
1792         $key = new xmldb_key('fk_user', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
1793         $dbman->add_key($table, $key);
1795         upgrade_main_savepoint(true, 2018062800.01);
1796     }
1798     if ($oldversion < 2018062800.02) {
1799         // Add composite index ix_concomitem to the table comments.
1800         $table = new xmldb_table('comments');
1801         $index = new xmldb_index('ix_concomitem', XMLDB_INDEX_NOTUNIQUE, array('contextid', 'commentarea', 'itemid'));
1803         if (!$dbman->index_exists($table, $index)) {
1804             $dbman->add_index($table, $index);
1805         }
1807         upgrade_main_savepoint(true, 2018062800.02);
1808     }
1810     if ($oldversion < 2018062800.03) {
1811         // Define field location to be added to event.
1812         $table = new xmldb_table('event');
1813         $field = new xmldb_field('location', XMLDB_TYPE_TEXT, null, null, null, null, null, 'priority');
1815         // Conditionally launch add field location.
1816         if (!$dbman->field_exists($table, $field)) {
1817             $dbman->add_field($table, $field);
1818         }
1820         // Main savepoint reached.
1821         upgrade_main_savepoint(true, 2018062800.03);
1822     }
1824     if ($oldversion < 2018072500.00) {
1825         // Find all duplicate top level categories per context.
1826         $duplicates = $DB->get_records_sql("SELECT qc1.*
1827                                               FROM {question_categories} qc1
1828                                               JOIN {question_categories} qc2
1829                                                 ON qc1.contextid = qc2.contextid AND qc1.id <> qc2.id
1830                                              WHERE qc1.parent = 0 AND qc2.parent = 0
1831                                           ORDER BY qc1.contextid, qc1.id");
1833         // For each context, let the first top category to remain as top category and make the rest its children.
1834         $currentcontextid = 0;
1835         $chosentopid = 0;
1836         foreach ($duplicates as $duplicate) {
1837             if ($currentcontextid != $duplicate->contextid) {
1838                 $currentcontextid = $duplicate->contextid;
1839                 $chosentopid = $duplicate->id;
1840             } else {
1841                 $DB->set_field('question_categories', 'parent', $chosentopid, ['id' => $duplicate->id]);
1842             }
1843         }
1845         // Main savepoint reached.
1846         upgrade_main_savepoint(true, 2018072500.00);
1847     }
1849     if ($oldversion < 2018073000.00) {
1850         // Main savepoint reached.
1851         if (!file_exists($CFG->dirroot . '/admin/tool/assignmentupgrade/version.php')) {
1852             unset_all_config_for_plugin('tool_assignmentupgrade');
1853         }
1854         upgrade_main_savepoint(true, 2018073000.00);
1855     }
1857     if ($oldversion < 2018083100.01) {
1858         // Remove module associated blog posts for non-existent (deleted) modules.
1859         $sql = "SELECT ba.contextid as modcontextid
1860                   FROM {blog_association} ba
1861                   JOIN {post} p
1862                        ON p.id = ba.blogid
1863              LEFT JOIN {context} c
1864                        ON c.id = ba.contextid
1865                  WHERE p.module = :module
1866                        AND c.contextlevel IS NULL
1867               GROUP BY ba.contextid";
1868         if ($deletedmodules = $DB->get_records_sql($sql, array('module' => 'blog'))) {
1869             foreach ($deletedmodules as $module) {
1870                 $assocblogids = $DB->get_fieldset_select('blog_association', 'blogid',
1871                     'contextid = :contextid', ['contextid' => $module->modcontextid]);
1872                 list($sql, $params) = $DB->get_in_or_equal($assocblogids, SQL_PARAMS_NAMED);
1874                 $DB->delete_records_select('tag_instance', "itemid $sql", $params);
1875                 $DB->delete_records_select('post', "id $sql AND module = :module",
1876                     array_merge($params, ['module' => 'blog']));
1877                 $DB->delete_records('blog_association', ['contextid' => $module->modcontextid]);
1878             }
1879         }
1881         // Main savepoint reached.
1882         upgrade_main_savepoint(true, 2018083100.01);
1883     }
1885     if ($oldversion < 2018091200.00) {
1886         if (!file_exists($CFG->dirroot . '/cache/stores/memcache/settings.php')) {
1887             unset_all_config_for_plugin('cachestore_memcache');
1888         }
1890         upgrade_main_savepoint(true, 2018091200.00);
1891     }
1893     if ($oldversion < 2018091700.01) {
1894         // Remove unused setting.
1895         unset_config('messaginghidereadnotifications');
1897         // Main savepoint reached.
1898         upgrade_main_savepoint(true, 2018091700.01);
1899     }
1901     // Add idnumber fields to question and question_category tables.
1902     // This is done in four parts to aid error recovery during upgrade, should that occur.
1903     if ($oldversion < 2018092100.01) {
1904         $table = new xmldb_table('question');
1905         $field = new xmldb_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'modifiedby');
1906         if (!$dbman->field_exists($table, $field)) {
1907             $dbman->add_field($table, $field);
1908         }
1909         upgrade_main_savepoint(true, 2018092100.01);
1910     }
1912     if ($oldversion < 2018092100.02) {
1913         $table = new xmldb_table('question');
1914         $index = new xmldb_index('categoryidnumber', XMLDB_INDEX_UNIQUE, array('category', 'idnumber'));
1915         if (!$dbman->index_exists($table, $index)) {
1916             $dbman->add_index($table, $index);
1917         }
1918         upgrade_main_savepoint(true, 2018092100.02);
1919     }
1921     if ($oldversion < 2018092100.03) {
1922         $table = new xmldb_table('question_categories');
1923         $field = new xmldb_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'sortorder');
1924         if (!$dbman->field_exists($table, $field)) {
1925             $dbman->add_field($table, $field);
1926         }
1927         upgrade_main_savepoint(true, 2018092100.03);
1928     }
1930     if ($oldversion < 2018092100.04) {
1931         $table = new xmldb_table('question_categories');
1932         $index = new xmldb_index('contextididnumber', XMLDB_INDEX_UNIQUE, array('contextid', 'idnumber'));
1933         if (!$dbman->index_exists($table, $index)) {
1934             $dbman->add_index($table, $index);
1935         }
1936         // Main savepoint reached.
1937         upgrade_main_savepoint(true, 2018092100.04);
1938     }
1940     if ($oldversion < 2018092800.00) {
1941         // Alter the table 'message_contacts'.
1942         $table = new xmldb_table('message_contacts');
1944         // Remove index so we can alter the fields.
1945         $index = new xmldb_index('userid-contactid', XMLDB_INDEX_UNIQUE, ['userid', 'contactid']);
1946         if ($dbman->index_exists($table, $index)) {
1947             $dbman->drop_index($table, $index);
1948         }
1950         // Remove defaults of '0' from the 'userid' and 'contactid' fields.
1951         $field = new xmldb_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
1952         $dbman->change_field_default($table, $field);
1954         $field = new xmldb_field('contactid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid');
1955         $dbman->change_field_default($table, $field);
1957         // Add the missing FKs that will now be added to new installs.
1958         $key = new xmldb_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
1959         $dbman->add_key($table, $key);
1961         $key = new xmldb_key('contactid', XMLDB_KEY_FOREIGN, ['contactid'], 'user', ['id']);
1962         $dbman->add_key($table, $key);
1964         // Re-add the index.
1965         if (!$dbman->index_exists($table, $index)) {
1966             $dbman->add_index($table, $index);
1967         }
1969         // Add the field 'timecreated'. Allow null, since existing records won't have an accurate value we can use.
1970         $field = new xmldb_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'blocked');
1971         if (!$dbman->field_exists($table, $field)) {
1972             $dbman->add_field($table, $field);
1973         }
1975         // Create new 'message_contact_requests' table.
1976         $table = new xmldb_table('message_contact_requests');
1977         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
1978         $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
1979         $table->add_field('requesteduserid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid');
1980         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'requesteduserid');
1982         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id'], null, null);
1983         $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
1984         $table->add_key('requesteduserid', XMLDB_KEY_FOREIGN, ['requesteduserid'], 'user', ['id']);
1986         $table->add_index('userid-requesteduserid', XMLDB_INDEX_UNIQUE, ['userid', 'requesteduserid']);
1988         if (!$dbman->table_exists($table)) {
1989             $dbman->create_table($table);
1990         }
1992         // Create new 'message_users_blocked' table.
1993         $table = new xmldb_table('message_users_blocked');
1994         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
1995         $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
1996         $table->add_field('blockeduserid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid');
1997         // Allow NULLs in the 'timecreated' field because we will be moving existing data here that has no timestamp.
1998         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'blockeduserid');
2000         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id'], null, null);
2001         $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
2002         $table->add_key('blockeduserid', XMLDB_KEY_FOREIGN, ['blockeduserid'], 'user', ['id']);
2004         $table->add_index('userid-blockeduserid', XMLDB_INDEX_UNIQUE, ['userid', 'blockeduserid']);
2006         if (!$dbman->table_exists($table)) {
2007             $dbman->create_table($table);
2008         }
2010         upgrade_main_savepoint(true, 2018092800.00);
2011     }
2013     if ($oldversion < 2018092800.01) {
2014         // Move all the 'blocked' contacts to the new table 'message_users_blocked'.
2015         $updatesql = "INSERT INTO {message_users_blocked} (userid, blockeduserid, timecreated)
2016                            SELECT userid, contactid, null as timecreated
2017                              FROM {message_contacts}
2018                             WHERE blocked = :blocked";
2019         $DB->execute($updatesql, ['blocked' => 1]);
2021         // Removed the 'blocked' column from 'message_contacts'.
2022         $table = new xmldb_table('message_contacts');
2023         $field = new xmldb_field('blocked');
2024         $dbman->drop_field($table, $field);
2026         upgrade_main_savepoint(true, 2018092800.01);
2027     }
2029     if ($oldversion < 2018092800.02) {
2030         // Delete any contacts that are not mutual (meaning they both haven't added each other).
2031         $sql = "SELECT c1.id
2032                   FROM {message_contacts} c1
2033              LEFT JOIN {message_contacts} c2
2034                     ON c1.userid = c2.contactid
2035                    AND c1.contactid = c2.userid
2036                  WHERE c2.id IS NULL";
2037         if ($contacts = $DB->get_records_sql($sql)) {
2038             list($insql, $inparams) = $DB->get_in_or_equal(array_keys($contacts));
2039             $DB->delete_records_select('message_contacts', "id $insql", $inparams);
2040         }
2042         upgrade_main_savepoint(true, 2018092800.02);
2043     }
2045     if ($oldversion < 2018092800.03) {
2046         // Remove any duplicate rows - from now on adding contacts just requires 1 row.
2047         // The person who made the contact request (userid) and the person who approved
2048         // it (contactid). Upgrade the table so that the first person to add the contact
2049         // was the one who made the request.
2050         $sql = "SELECT c1.id
2051                   FROM {message_contacts} c1
2052             INNER JOIN {message_contacts} c2
2053                     ON c1.userid = c2.contactid
2054                    AND c1.contactid = c2.userid
2055                  WHERE c1.id > c2.id";
2056         if ($contacts = $DB->get_records_sql($sql)) {
2057             list($insql, $inparams) = $DB->get_in_or_equal(array_keys($contacts));
2058             $DB->delete_records_select('message_contacts', "id $insql", $inparams);
2059         }
2061         upgrade_main_savepoint(true, 2018092800.03);
2062     }
2064     if ($oldversion < 2018101700.01) {
2065         if (empty($CFG->keepmessagingallusersenabled)) {
2066             // When it is not set, $CFG->messagingallusers should be disabled by default.
2067             // When $CFG->messagingallusers = false, the default user preference is MESSAGE_PRIVACY_COURSEMEMBER
2068             // (contacted by users sharing a course).
2069             set_config('messagingallusers', false);
2070         } else {
2071             // When $CFG->keepmessagingallusersenabled is set to true, $CFG->messagingallusers is set to true.
2072             set_config('messagingallusers', true);
2074             // When $CFG->messagingallusers = true, the default user preference is MESSAGE_PRIVACY_SITE
2075             // (contacted by all users site). So we need to set existing values from 0 (MESSAGE_PRIVACY_COURSEMEMBER)
2076             // to 2 (MESSAGE_PRIVACY_SITE).
2077             $DB->set_field(
2078                 'user_preferences',
2079                 'value',
2080                 \core_message\api::MESSAGE_PRIVACY_SITE,
2081                 array('name' => 'message_blocknoncontacts', 'value' => 0)
2082             );
2083         }
2085         // Main savepoint reached.
2086         upgrade_main_savepoint(true, 2018101700.01);
2087     }
2089     if ($oldversion < 2018101800.00) {
2090         // Define table 'favourite' to be created.
2091         $table = new xmldb_table('favourite');
2093         // Adding fields to table favourite.
2094         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2095         $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
2096         $table->add_field('itemtype', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
2097         $table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2098         $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2099         $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2100         $table->add_field('ordering', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2101         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2102         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2104         // Adding keys to table favourite.
2105         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2106         $table->add_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']);
2107         $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
2109         // Adding indexes to table favourite.
2110         $table->add_index('uniqueuserfavouriteitem', XMLDB_INDEX_UNIQUE, ['component', 'itemtype', 'itemid', 'contextid', 'userid']);
2112         // Conditionally launch create table for favourite.
2113         if (!$dbman->table_exists($table)) {
2114             $dbman->create_table($table);
2115         }
2117         // Main savepoint reached.
2118         upgrade_main_savepoint(true, 2018101800.00);
2119     }
2121     if ($oldversion < 2018102200.00) {
2122         // Add field 'type' to 'message_conversations'.
2123         $table = new xmldb_table('message_conversations');
2124         $field = new xmldb_field('type', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 1, 'id');
2125         if (!$dbman->field_exists($table, $field)) {
2126             $dbman->add_field($table, $field);
2127         }
2129         // Add field 'name' to 'message_conversations'.
2130         $field = new xmldb_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'type');
2131         if (!$dbman->field_exists($table, $field)) {
2132             $dbman->add_field($table, $field);
2133         }
2135         // Conditionally launch add index 'type'.
2136         $index = new xmldb_index('type', XMLDB_INDEX_NOTUNIQUE, ['type']);
2137         if (!$dbman->index_exists($table, $index)) {
2138             $dbman->add_index($table, $index);
2139         }
2141         // Define table 'message_conversations' to be updated.
2142         $table = new xmldb_table('message_conversations');
2144         // Remove the unique 'convhash' index, change to null and add a new non unique index.
2145         $index = new xmldb_index('convhash', XMLDB_INDEX_UNIQUE, ['convhash']);
2146         if ($dbman->index_exists($table, $index)) {
2147             $dbman->drop_index($table, $index);
2148         }
2150         $field = new xmldb_field('convhash', XMLDB_TYPE_CHAR, '40', null, null, null, null, 'name');
2151         $dbman->change_field_notnull($table, $field);
2153         $index = new xmldb_index('convhash', XMLDB_INDEX_NOTUNIQUE, ['convhash']);
2154         if (!$dbman->index_exists($table, $index)) {
2155             $dbman->add_index($table, $index);
2156         }
2158         upgrade_main_savepoint(true, 2018102200.00);
2159     }
2161     if ($oldversion < 2018102300.02) {
2162         // Alter 'message_conversations' table to support groups.
2163         $table = new xmldb_table('message_conversations');
2164         $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'convhash');
2165         if (!$dbman->field_exists($table, $field)) {
2166             $dbman->add_field($table, $field);
2167         }
2169         $field = new xmldb_field('itemtype', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'component');
2170         if (!$dbman->field_exists($table, $field)) {
2171             $dbman->add_field($table, $field);
2172         }
2174         $field = new xmldb_field('itemid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'itemtype');
2175         if (!$dbman->field_exists($table, $field)) {
2176             $dbman->add_field($table, $field);
2177         }
2179         $field = new xmldb_field('contextid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'itemid');
2180         if (!$dbman->field_exists($table, $field)) {
2181             $dbman->add_field($table, $field);
2182         }
2184         $field = new xmldb_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, 0, 'contextid');
2185         if (!$dbman->field_exists($table, $field)) {
2186             $dbman->add_field($table, $field);
2187         }
2189         $field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'enabled');
2190         if (!$dbman->field_exists($table, $field)) {
2191             $dbman->add_field($table, $field);
2192         }
2194         // Add key.
2195         $key = new xmldb_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']);
2196         $dbman->add_key($table, $key);
2198         // Add index.
2199         $index = new xmldb_index('component-itemtype-itemid-contextid', XMLDB_INDEX_NOTUNIQUE, ['component', 'itemtype',
2200             'itemid', 'contextid']);
2201         if (!$dbman->index_exists($table, $index)) {
2202             $dbman->add_index($table, $index);
2203         }
2205         upgrade_main_savepoint(true, 2018102300.02);
2206     }
2208     if ($oldversion < 2018102900.00) {
2209         // Define field predictionsprocessor to be added to analytics_models.
2210         $table = new xmldb_table('analytics_models');
2211         $field = new xmldb_field('predictionsprocessor', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'timesplitting');
2213         // Conditionally launch add field predictionsprocessor.
2214         if (!$dbman->field_exists($table, $field)) {
2215             $dbman->add_field($table, $field);
2216         }
2218         // Main savepoint reached.
2219         upgrade_main_savepoint(true, 2018102900.00);
2220     }
2222     if ($oldversion < 2018110500.01) {
2223         // Define fields to be added to the 'badge' table.
2224         $tablebadge = new xmldb_table('badge');
2225         $fieldversion = new xmldb_field('version', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'nextcron');
2226         $fieldlanguage = new xmldb_field('language', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'version');
2227         $fieldimageauthorname = new xmldb_field('imageauthorname', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'language');
2228         $fieldimageauthoremail = new xmldb_field('imageauthoremail', XMLDB_TYPE_CHAR, '255', null, null,
2229             null, null, 'imageauthorname');
2230         $fieldimageauthorurl = new xmldb_field('imageauthorurl', XMLDB_TYPE_CHAR, '255', null, null,
2231             null, null, 'imageauthoremail');
2232         $fieldimagecaption = new xmldb_field('imagecaption', XMLDB_TYPE_TEXT, null, null, null, null, null, 'imageauthorurl');
2234         if (!$dbman->field_exists($tablebadge, $fieldversion)) {
2235             $dbman->add_field($tablebadge, $fieldversion);
2236         }
2237         if (!$dbman->field_exists($tablebadge, $fieldlanguage)) {
2238             $dbman->add_field($tablebadge, $fieldlanguage);
2239         }
2240         if (!$dbman->field_exists($tablebadge, $fieldimageauthorname)) {
2241             $dbman->add_field($tablebadge, $fieldimageauthorname);
2242         }
2243         if (!$dbman->field_exists($tablebadge, $fieldimageauthoremail)) {
2244             $dbman->add_field($tablebadge, $fieldimageauthoremail);
2245         }
2246         if (!$dbman->field_exists($tablebadge, $fieldimageauthorurl)) {
2247             $dbman->add_field($tablebadge, $fieldimageauthorurl);
2248         }
2249         if (!$dbman->field_exists($tablebadge, $fieldimagecaption)) {
2250             $dbman->add_field($tablebadge, $fieldimagecaption);
2251         }
2253         // Define table badge_endorsement to be created.
2254         $table = new xmldb_table('badge_endorsement');
2256         // Adding fields to table badge_endorsement.
2257         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2258         $table->add_field('badgeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
2259         $table->add_field('issuername', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2260         $table->add_field('issuerurl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2261         $table->add_field('issueremail', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2262         $table->add_field('claimid', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2263         $table->add_field('claimcomment', XMLDB_TYPE_TEXT, null, null, null, null, null);
2264         $table->add_field('dateissued', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
2266         // Adding keys to table badge_endorsement.
2267         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2268         $table->add_key('endorsementbadge', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']);
2270         // Conditionally launch create table for badge_endorsement.
2271         if (!$dbman->table_exists($table)) {
2272             $dbman->create_table($table);
2273         }
2275         // Define table badge_related to be created.
2276         $table = new xmldb_table('badge_related');
2278         // Adding fields to table badge_related.
2279         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2280         $table->add_field('badgeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
2281         $table->add_field('relatedbadgeid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2283         // Adding keys to table badge_related.
2284         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2285         $table->add_key('badgeid', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']);
2286         $table->add_key('relatedbadgeid', XMLDB_KEY_FOREIGN, ['relatedbadgeid'], 'badge', ['id']);
2287         $table->add_key('badgeid-relatedbadgeid', XMLDB_KEY_UNIQUE, ['badgeid', 'relatedbadgeid']);
2289         // Conditionally launch create table for badge_related.
2290         if (!$dbman->table_exists($table)) {
2291             $dbman->create_table($table);
2292         }
2294         // Define table badge_competencies to be created.
2295         $table = new xmldb_table('badge_competencies');
2297         // Adding fields to table badge_competencies.
2298         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2299         $table->add_field('badgeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
2300         $table->add_field('targetname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2301         $table->add_field('targeturl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2302         $table->add_field('targetdescription', XMLDB_TYPE_TEXT, null, null, null, null, null);
2303         $table->add_field('targetframework', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2304         $table->add_field('targetcode', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2306         // Adding keys to table badge_competencies.
2307         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2308         $table->add_key('competenciesbadge', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']);
2310         // Conditionally launch create table for badge_competencies.
2311         if (!$dbman->table_exists($table)) {
2312             $dbman->create_table($table);
2313         }
2315         // Main savepoint reached.
2316         upgrade_main_savepoint(true, 2018110500.01);
2317     }
2319     if ($oldversion < 2018110700.01) {
2320         // This config setting added and then removed.
2321         unset_config('showcourseimages', 'moodlecourse');
2323         // Main savepoint reached.
2324         upgrade_main_savepoint(true, 2018110700.01);
2325     }
2327     if ($oldversion < 2018111301.00) {
2328         // Define field locked to be added to context.
2329         $table = new xmldb_table('context');
2330         $field = new xmldb_field('locked', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'depth');
2332         // Conditionally launch add field locked.
2333         if (!$dbman->field_exists($table, $field)) {
2334             $dbman->add_field($table, $field);
2335         }
2337         // Define field locked to be added to context_temp.
2338         $table = new xmldb_table('context_temp');
2339         $field = new xmldb_field('locked', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'depth');
2341         // Conditionally launch add field locked.
2342         if (!$dbman->field_exists($table, $field)) {
2343             $dbman->add_field($table, $field);
2344         }
2346         // Note: This change also requires a bump in is_major_upgrade_required.
2347         upgrade_main_savepoint(true, 2018111301.00);
2348     }
2350     if ($oldversion < 2018111900.00) {
2351         // Update favourited courses, so they are saved in the particular course context instead of the system.
2352         $favouritedcourses = $DB->get_records('favourite', ['component' => 'core_course', 'itemtype' => 'courses']);
2354         foreach ($favouritedcourses as $fc) {
2355             $coursecontext = \context_course::instance($fc->itemid);
2356             $fc->contextid = $coursecontext->id;
2357             $DB->update_record('favourite', $fc);
2358         }
2360         upgrade_main_savepoint(true, 2018111900.00);
2361     }
2363     if ($oldversion < 2018111900.01) {
2364         // Define table oauth2_access_token to be created.
2365         $table = new xmldb_table('oauth2_access_token');
2367         // Adding fields to table oauth2_access_token.
2368         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2369         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2370         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2371         $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2372         $table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2373         $table->add_field('token', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
2374         $table->add_field('expires', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2375         $table->add_field('scope', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
2377         // Adding keys to table oauth2_access_token.
2378         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2379         $table->add_key('issueridkey', XMLDB_KEY_FOREIGN_UNIQUE, ['issuerid'], 'oauth2_issuer', ['id']);
2381         // Conditionally launch create table for oauth2_access_token.
2382         if (!$dbman->table_exists($table)) {
2383             $dbman->create_table($table);
2384         }
2386         // Main savepoint reached.
2387         upgrade_main_savepoint(true, 2018111900.01);
2388     }
2390     if ($oldversion < 2018112000.00) {
2391         // Update favourited conversations, so they are saved in the proper context instead of the system.
2392         $sql = "SELECT f.*, mc.contextid as conversationctx
2393                   FROM {favourite} f
2394                   JOIN {message_conversations} mc
2395                     ON mc.id = f.itemid";
2396         $favouritedconversations = $DB->get_records_sql($sql);
2397         foreach ($favouritedconversations as $fc) {
2398             if (empty($fc->conversationctx)) {
2399                 $conversationidctx = \context_user::instance($fc->userid)->id;
2400             } else {
2401                 $conversationidctx = $fc->conversationctx;
2402             }
2404             $DB->set_field('favourite', 'contextid', $conversationidctx, ['id' => $fc->id]);
2405         }
2407         upgrade_main_savepoint(true, 2018112000.00);
2408     }
2410     // Automatically generated Moodle v3.6.0 release upgrade line.
2411     // Put any upgrade step following this.
2413     if ($oldversion < 2018120300.01) {
2414         // Update the FB logo URL.
2415         $oldurl = 'https://facebookbrand.com/wp-content/themes/fb-branding/prj-fb-branding/assets/images/fb-art.png';
2416         $newurl = 'https://facebookbrand.com/wp-content/uploads/2016/05/flogo_rgb_hex-brc-site-250.png';
2418         $updatesql = "UPDATE {oauth2_issuer}
2419                          SET image = :newimage
2420                        WHERE " . $DB->sql_compare_text('image', 100). " = :oldimage";
2421         $params = [
2422             'newimage' => $newurl,
2423             'oldimage' => $oldurl
2424         ];
2425         $DB->execute($updatesql, $params);
2427         upgrade_main_savepoint(true, 2018120300.01);
2428     }
2430     if ($oldversion < 2018120300.02) {
2431         // Set all individual conversations to enabled.
2432         $updatesql = "UPDATE {message_conversations}
2433                          SET enabled = :enabled
2434                        WHERE type = :type";
2435         $DB->execute($updatesql, ['enabled' => 1, 'type' => 1]);
2437         upgrade_main_savepoint(true, 2018120300.02);
2438     }
2440     if ($oldversion < 2018120301.02) {
2441         upgrade_delete_orphaned_file_records();
2442         upgrade_main_savepoint(true, 2018120301.02);
2443     }
2445     if ($oldversion < 2019011500.00) {
2446         // Define table task_log to be created.
2447         $table = new xmldb_table('task_log');
2449         // Adding fields to table task_log.
2450         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2451         $table->add_field('type', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, null);
2452         $table->add_field('component', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2453         $table->add_field('classname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2454         $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2455         $table->add_field('timestart', XMLDB_TYPE_NUMBER, '20, 10', null, XMLDB_NOTNULL, null, null);
2456         $table->add_field('timeend', XMLDB_TYPE_NUMBER, '20, 10', null, XMLDB_NOTNULL, null, null);
2457         $table->add_field('dbreads', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2458         $table->add_field('dbwrites', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2459         $table->add_field('result', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, null);
2461         // Adding keys to table task_log.
2462         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2464         // Adding indexes to table task_log.
2465         $table->add_index('classname', XMLDB_INDEX_NOTUNIQUE, ['classname']);
2466         $table->add_index('timestart', XMLDB_INDEX_NOTUNIQUE, ['timestart']);
2468         // Conditionally launch create table for task_log.
2469         if (!$dbman->table_exists($table)) {
2470             $dbman->create_table($table);
2471         }
2473         // Main savepoint reached.
2474         upgrade_main_savepoint(true, 2019011500.00);
2475     }
2477     if ($oldversion < 2019011501.00) {
2478         // Define field output to be added to task_log.
2479         $table = new xmldb_table('task_log');
2480         $field = new xmldb_field('output', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null, 'result');
2482         // Conditionally launch add field output.
2483         if (!$dbman->field_exists($table, $field)) {
2484             $dbman->add_field($table, $field);
2485         }
2487         // Main savepoint reached.
2488         upgrade_main_savepoint(true, 2019011501.00);
2489     }
2491     if ($oldversion < 2019011801.00) {
2493         // Define table customfield_category to be created.
2494         $table = new xmldb_table('customfield_category');
2496         // Adding fields to table customfield_category.
2497         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2498         $table->add_field('name', XMLDB_TYPE_CHAR, '400', null, XMLDB_NOTNULL, null, null);
2499         $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
2500         $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2501         $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2502         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2503         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2504         $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
2505         $table->add_field('area', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
2506         $table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
2507         $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2509         // Adding keys to table customfield_category.
2510         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2511         $table->add_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']);
2513         // Adding indexes to table customfield_category.
2514         $table->add_index('component_area_itemid', XMLDB_INDEX_NOTUNIQUE, ['component', 'area', 'itemid', 'sortorder']);
2516         // Conditionally launch create table for customfield_category.
2517         if (!$dbman->table_exists($table)) {
2518             $dbman->create_table($table);
2519         }
2521         // Define table customfield_field to be created.
2522         $table = new xmldb_table('customfield_field');
2524         // Adding fields to table customfield_field.
2525         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2526         $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
2527         $table->add_field('name', XMLDB_TYPE_CHAR, '400', null, XMLDB_NOTNULL, null, null);
2528         $table->add_field('type', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
2529         $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
2530         $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2531         $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2532         $table->add_field('categoryid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2533         $table->add_field('configdata', XMLDB_TYPE_TEXT, null, null, null, null, null);
2534         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2535         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2537         // Adding keys to table customfield_field.
2538         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2539         $table->add_key('categoryid', XMLDB_KEY_FOREIGN, ['categoryid'], 'customfield_category', ['id']);
2541         // Adding indexes to table customfield_field.
2542         $table->add_index('categoryid_sortorder', XMLDB_INDEX_NOTUNIQUE, ['categoryid', 'sortorder']);
2544         // Conditionally launch create table for customfield_field.
2545         if (!$dbman->table_exists($table)) {
2546             $dbman->create_table($table);
2547         }
2549         // Define table customfield_data to be created.
2550         $table = new xmldb_table('customfield_data');
2552         // Adding fields to table customfield_data.
2553         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2554         $table->add_field('fieldid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2555         $table->add_field('instanceid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2556         $table->add_field('intvalue', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2557         $table->add_field('decvalue', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null);
2558         $table->add_field('shortcharvalue', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2559         $table->add_field('charvalue', XMLDB_TYPE_CHAR, '1333', null, null, null, null);
2560         $table->add_field('value', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
2561         $table->add_field('valueformat', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2562         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2563         $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2564         $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
2566         // Adding keys to table customfield_data.
2567         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2568         $table->add_key('fieldid', XMLDB_KEY_FOREIGN, ['fieldid'], 'customfield_field', ['id']);
2569         $table->add_key('contextid', XMLDB_KEY_FOREIGN, ['contextid'], 'context', ['id']);
2571         // Adding indexes to table customfield_data.
2572         $table->add_index('instanceid-fieldid', XMLDB_INDEX_UNIQUE, ['instanceid', 'fieldid']);
2573         $table->add_index('fieldid-intvalue', XMLDB_INDEX_NOTUNIQUE, ['fieldid', 'intvalue']);
2574         $table->add_index('fieldid-shortcharvalue', XMLDB_INDEX_NOTUNIQUE, ['fieldid', 'shortcharvalue']);
2575         $table->add_index('fieldid-decvalue', XMLDB_INDEX_NOTUNIQUE, ['fieldid', 'decvalue']);
2577         // Conditionally launch create table for customfield_data.
2578         if (!$dbman->table_exists($table)) {
2579             $dbman->create_table($table);
2580         }
2582         upgrade_main_savepoint(true, 2019011801.00);
2583     }
2585     if ($oldversion < 2019011801.01) {
2587         // Delete all files that have been used in sections, which are already deleted.
2588         $sql = "SELECT DISTINCT f.itemid as sectionid, f.contextid
2589                   FROM {files} f
2590              LEFT JOIN {course_sections} s ON f.itemid = s.id
2591                  WHERE f.component = :component AND f.filearea = :filearea AND s.id IS NULL ";
2593         $params = [
2594             'component' => 'course',
2595             'filearea' => 'section'
2596         ];
2598         $stalefiles = $DB->get_recordset_sql($sql, $params);
2600         $fs = get_file_storage();
2601         foreach ($stalefiles as $stalefile) {
2602             $fs->delete_area_files($stalefile->contextid, 'course', 'section', $stalefile->sectionid);
2603         }
2604         $stalefiles->close();
2606         upgrade_main_savepoint(true, 2019011801.01);
2607     }
2609     if ($oldversion < 2019011801.02) {
2610         // Add index 'useridfrom' to the table 'notifications'.
2611         $table = new xmldb_table('notifications');
2612         $index = new xmldb_index('useridfrom', XMLDB_INDEX_NOTUNIQUE, ['useridfrom']);
2614         if (!$dbman->index_exists($table, $index)) {
2615             $dbman->add_index($table, $index);
2616         }
2618         upgrade_main_savepoint(true, 2019011801.02);
2619     }
2621     if ($oldversion < 2019011801.03) {
2622         // Remove duplicate entries from group memberships.
2623         // Find records with multiple userid/groupid combinations and find the highest ID.
2624         // Later we will remove all those entries.
2625         $sql = "
2626             SELECT MIN(id) as minid, userid, groupid
2627             FROM {groups_members}
2628             GROUP BY userid, groupid
2629             HAVING COUNT(id) > 1";
2630         if ($duplicatedrows = $DB->get_recordset_sql($sql)) {
2631             foreach ($duplicatedrows as $row) {
2632                 $DB->delete_records_select('groups_members',
2633                     'userid = :userid AND groupid = :groupid AND id <> :minid', (array)$row);
2634             }
2635         }
2636         $duplicatedrows->close();
2638         // Define key useridgroupid (unique) to be added to group_members.
2639         $table = new xmldb_table('groups_members');
2640         $key = new xmldb_key('useridgroupid', XMLDB_KEY_UNIQUE, array('userid', 'groupid'));
2641         // Launch add key useridgroupid.
2642         $dbman->add_key($table, $key);
2643         // Main savepoint reached.
2644         upgrade_main_savepoint(true, 2019011801.03);
2645     }
2647     if ($oldversion < 2019021500.01) {
2648         $insights = $DB->get_record('message_providers', ['component' => 'moodle', 'name' => 'insights']);
2649         if (!empty($insights)) {
2650             $insights->capability = null;
2651             $DB->update_record('message_providers', $insights);
2652         }
2653         upgrade_main_savepoint(true, 2019021500.01);
2654     }
2656     if ($oldversion < 2019021500.02) {
2657         // Default 'off' for existing sites as this is the behaviour they had earlier.
2658         set_config('messagingdefaultpressenter', false);
2660         // Main savepoint reached.
2661         upgrade_main_savepoint(true, 2019021500.02);
2662     }
2664     if ($oldversion < 2019030100.01) {
2665         // Create adhoc task to delete renamed My Course search area (ID core_course-mycourse).
2666         $record = new \stdClass();
2667         $record->classname = '\core\task\clean_up_deleted_search_area_task';
2668         $record->component = 'core';
2670         // Next run time based from nextruntime computation in \core\task\manager::queue_adhoc_task().
2671         $nextruntime = time() - 1;
2672         $record->nextruntime = $nextruntime;
2673         $record->customdata = json_encode('core_course-mycourse');
2675         $DB->insert_record('task_adhoc', $record);
2677         // Main savepoint reached.
2678         upgrade_main_savepoint(true, 2019030100.01);
2679     }
2681     if ($oldversion < 2019030700.01) {
2683         // Define field evaluationmode to be added to analytics_models_log.
2684         $table = new xmldb_table('analytics_models_log');
2685         $field = new xmldb_field('evaluationmode', XMLDB_TYPE_CHAR, '50', null, null, null,
2686             null, 'version');
2688         // Conditionally launch add field evaluationmode.
2689         if (!$dbman->field_exists($table, $field)) {
2690             $dbman->add_field($table, $field);
2692             $updatesql = "UPDATE {analytics_models_log}
2693                              SET evaluationmode = 'configuration'";
2694             $DB->execute($updatesql, []);
2696             // Changing nullability of field evaluationmode on table block_instances to not null.
2697             $field = new xmldb_field('evaluationmode', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL,
2698                 null, null, 'version');
2700             // Launch change of nullability for field evaluationmode.
2701             $dbman->change_field_notnull($table, $field);
2702         }
2704         // Main savepoint reached.
2705         upgrade_main_savepoint(true, 2019030700.01);
2706     }
2708     if ($oldversion < 2019030800.00) {
2709         // Define table 'message_conversation_actions' to be created.
2710         // Note - I would have preferred 'message_conversation_user_actions' but due to Oracle we can't. Boo.
2711         $table = new xmldb_table('message_conversation_actions');
2713         // Adding fields to table 'message_conversation_actions'.
2714         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2715         $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2716         $table->add_field('conversationid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2717         $table->add_field('action', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2718         $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
2720         // Adding keys to table 'message_conversation_actions'.
2721         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
2722         $table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
2723         $table->add_key('conversationid', XMLDB_KEY_FOREIGN, ['conversationid'], 'message_conversations', ['id']);
2725         // Conditionally launch create table for 'message_conversation_actions'.
2726         if (!$dbman->table_exists($table)) {
2727             $dbman->create_table($table);
2728         }
2730         // Main savepoint reached.
2731         upgrade_main_savepoint(true, 2019030800.00);
2732     }
2734     if ($oldversion < 2019030800.02) {
2735         // Remove any conversations and their members associated with non-existent groups.
2736         $sql = "SELECT mc.id
2737                   FROM {message_conversations} mc
2738              LEFT JOIN {groups} g
2739                     ON mc.itemid = g.id
2740                  WHERE mc.component = :component
2741                    AND mc.itemtype = :itemtype
2742                    AND g.id is NULL";
2743         $conversations = $DB->get_records_sql($sql, ['component' => 'core_group', 'itemtype' => 'groups']);
2745         if ($conversations) {
2746             $conversationids = array_keys($conversations);
2748             $DB->delete_records_list('message_conversations', 'id', $conversationids);
2749             $DB->delete_records_list('message_conversation_members', 'conversationid', $conversationids);
2750             $DB->delete_records_list('message_conversation_actions', 'conversationid', $conversationids);
2752             // Now, go through each conversation and delete any messages and related message actions.
2753             foreach ($conversationids as $conversationid) {
2754                 if ($messages = $DB->get_records('messages', ['conversationid' => $conversationid])) {
2755                     $messageids = array_keys($messages);
2757                     // Delete the actions.
2758                     list($insql, $inparams) = $DB->get_in_or_equal($messageids);
2759                     $DB->delete_records_select('message_user_actions', "messageid $insql", $inparams);
2761                     // Delete the messages.
2762                     $DB->delete_records('messages', ['conversationid' => $conversationid]);
2763                 }
2764             }
2765         }
2767         // Main savepoint reached.
2768         upgrade_main_savepoint(true, 2019030800.02);
2769     }
2771     if ($oldversion < 2019030800.03) {
2773         // Add missing indicators to course_dropout.
2774         $params = [
2775             'target' => '\core\analytics\target\course_dropout',
2776             'trained' => 0,
2777             'enabled' => 0,
2778         ];
2779         $models = $DB->get_records('analytics_models', $params);
2780         foreach ($models as $model) {
2781             $indicators = json_decode($model->indicators);
2783             $potentiallymissingindicators = [
2784                 '\core_course\analytics\indicator\completion_enabled',
2785                 '\core_course\analytics\indicator\potential_cognitive_depth',
2786                 '\core_course\analytics\indicator\potential_social_breadth',
2787                 '\core\analytics\indicator\any_access_after_end',
2788                 '\core\analytics\indicator\any_access_before_start',
2789                 '\core\analytics\indicator\any_write_action_in_course',
2790                 '\core\analytics\indicator\read_actions'
2791             ];
2793             $missing = false;
2794             foreach ($potentiallymissingindicators as $potentiallymissingindicator) {
2795                 if (!in_array($potentiallymissingindicator, $indicators)) {
2796                     // Add the missing indicator to sites upgraded before 2017072000.02.
2797                     $indicators[] = $potentiallymissingindicator;
2798                     $missing = true;
2799                 }
2800             }
2802             if ($missing) {
2803                 $model->indicators = json_encode($indicators);
2804                 $model->version = time();
2805                 $model->timemodified = time();
2806                 $DB->update_record('analytics_models', $model);
2807             }
2808         }
2810         // Add missing indicators to no_teaching.
2811         $params = [
2812             'target' => '\core\analytics\target\no_teaching',
2813         ];
2814         $models = $DB->get_records('analytics_models', $params);
2815         foreach ($models as $model) {
2816             $indicators = json_decode($model->indicators);
2817             if (!in_array('\core_course\analytics\indicator\no_student', $indicators)) {
2818                 // Add the missing indicator to sites upgraded before 2017072000.02.
2820                 $indicators[] = '\core_course\analytics\indicator\no_student';
2822                 $model->indicators = json_encode($indicators);
2823                 $model->version = time();
2824                 $model->timemodified = time();
2825                 $DB->update_record('analytics_models', $model);
2826             }
2827         }
2829         // Main savepoint reached.
2830         upgrade_main_savepoint(true, 2019030800.03);
2831     }
2833     if ($oldversion < 2019031500.01) {
2835         $defaulttimesplittings = get_config('analytics', 'timesplittings');
2836         if ($defaulttimesplittings !== false) {
2837             set_config('defaulttimesplittingsevaluation', $defaulttimesplittings, 'analytics');
2838             unset_config('timesplittings', 'analytics');
2839         }
2841         // Main savepoint reached.
2842         upgrade_main_savepoint(true, 2019031500.01);
2843     }
2845     if ($oldversion < 2019032200.02) {
2846         // The no_teaching model might have been marked as not-trained by mistake (static models are always trained).
2847         $DB->set_field('analytics_models', 'trained', 1, ['target' => '\core\analytics\target\no_teaching']);
2848         upgrade_main_savepoint(true, 2019032200.02);
2849     }
2851     if ($oldversion < 2019032900.00) {
2853         // Define table badge_competencies to be renamed to badge_alignment.
2854         $table = new xmldb_table('badge_competencies');
2856         // Be careful if this step gets run twice.
2857         if ($dbman->table_exists($table)) {
2858             $key = new xmldb_key('competenciesbadge', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']);
2860             // Launch drop key competenciesbadge.
2861             $dbman->drop_key($table, $key);
2863             $key = new xmldb_key('alignmentsbadge', XMLDB_KEY_FOREIGN, ['badgeid'], 'badge', ['id']);
2865             // Launch add key alignmentsbadge.
2866             $dbman->add_key($table, $key);
2868             // Launch rename table for badge_alignment.
2869             $dbman->rename_table($table, 'badge_alignment');
2870         }
2872         upgrade_main_savepoint(true, 2019032900.00);
2873     }
2875     if ($oldversion < 2019032900.01) {
2876         $sql = "UPDATE {task_scheduled}
2877                    SET classname = ?
2878                  WHERE component = ?
2879                    AND classname = ?";
2880         $DB->execute($sql, [
2881             '\core\task\question_preview_cleanup_task',
2882             'moodle',
2883             '\core\task\question_cron_task'
2884         ]);
2886         // Main savepoint reached.
2887         upgrade_main_savepoint(true, 2019032900.01);
2888      }
2890     if ($oldversion < 2019040200.01) {
2891         // Removing the themes BSB, Clean, More from core.
2892         // If these theme wish to be retained empty this array before upgrade.
2893         $themes = array('theme_bootstrapbase' => 'bootstrapbase',
2894                 'theme_clean' => 'clean', 'theme_more' => 'more');
2895         foreach ($themes as $key => $theme) {
2896             if (check_dir_exists($CFG->dirroot . '/theme/' . $theme, false)) {
2897                 // Ignore the themes that have been re-downloaded.
2898                 unset($themes[$key]);
2899             }
2900         }
2901         // Check we actually have themes to remove.
2902         if (count($themes) > 0) {
2903             list($insql, $inparams) = $DB->get_in_or_equal($themes, SQL_PARAMS_NAMED);
2905             // Replace the theme usage.
2906             $DB->set_field_select('course', 'theme', 'classic', "theme $insql", $inparams);
2907             $DB->set_field_select('course_categories', 'theme', 'classic', "theme $insql", $inparams);
2908             $DB->set_field_select('user', 'theme', 'classic', "theme $insql", $inparams);
2909             $DB->set_field_select('mnet_host', 'theme', 'classic', "theme $insql", $inparams);
2910             $DB->set_field_select('cohort', 'theme', 'classic', "theme $insql", $inparams);
2912             // Replace the theme configs.
2913             if (in_array(get_config('core', 'theme'), $themes)) {
2914                 set_config('theme', 'classic');
2915             }
2916             if (in_array(get_config('core', 'thememobile'), $themes)) {
2917                 set_config('thememobile', 'classic');
2918             }
2919             if (in_array(get_config('core', 'themelegacy'), $themes)) {
2920                 set_config('themelegacy', 'classic');
2921             }
2922             if (in_array(get_config('core', 'themetablet'), $themes)) {
2923                 set_config('themetablet', 'classic');
2924             }
2926             // Hacky emulation of plugin uninstallation.
2927             foreach ($themes as $key => $theme) {
2928                 unset_all_config_for_plugin($key);
2929             }
2930         }
2932         // Main savepoint reached.
2933         upgrade_main_savepoint(true, 2019040200.01);
2934     }
2936     if ($oldversion < 2019040600.02) {
2938         // Define key fileid (foreign) to be dropped form analytics_train_samples.
2939         $table = new xmldb_table('analytics_train_samples');
2940         $key = new xmldb_key('fileid', XMLDB_KEY_FOREIGN, ['fileid'], 'files', ['id']);
2942         // Launch drop key fileid.
2943         $dbman->drop_key($table, $key);
2945         // Define field fileid to be dropped from analytics_train_samples.
2946         $table = new xmldb_table('analytics_train_samples');
2947         $field = new xmldb_field('fileid');
2949         // Conditionally launch drop field fileid.
2950         if ($dbman->field_exists($table, $field)) {
2951             $dbman->drop_field($table, $field);
2952         }
2954         // Main savepoint reached.
2955         upgrade_main_savepoint(true, 2019040600.02);
2956     }
2958     if ($oldversion < 2019040600.04) {
2959         // Define field and index to be added to backup_controllers.
2960         $table = new xmldb_table('backup_controllers');
2961         $field = new xmldb_field('progress', XMLDB_TYPE_NUMBER, '15, 14', null, XMLDB_NOTNULL, null, '0', 'timemodified');
2962         $index = new xmldb_index('useritem_ix', XMLDB_INDEX_NOTUNIQUE, ['userid', 'itemid']);
2963         // Conditionally launch add field progress.
2964         if (!$dbman->field_exists($table, $field)) {
2965             $dbman->add_field($table, $field);
2966         }
2967         // Conditionally launch add index useritem_ix.
2968         if (!$dbman->index_exists($table, $index)) {
2969             $dbman->add_index($table, $index);
2970         }
2972         // Main savepoint reached.
2973         upgrade_main_savepoint(true, 2019040600.04);
2974     }
2976     if ($oldversion < 2019041000.02) {
2978         // Define field fullmessagetrust to be added to messages.
2979         $table = new xmldb_table('messages');
2980         $field = new xmldb_field('fullmessagetrust', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'timecreated');
2982         // Conditionally launch add field fullmessagetrust.
2983         if (!$dbman->field_exists($table, $field)) {
2984             $dbman->add_field($table, $field);
2985         }
2987         // Main savepoint reached.
2988         upgrade_main_savepoint(true, 2019041000.02);
2989     }
2991     if ($oldversion < 2019041300.01) {
2992         // Add the field 'name' to the 'analytics_models' table.
2993         $table = new xmldb_table('analytics_models');
2994         $field = new xmldb_field('name', XMLDB_TYPE_CHAR, '1333', null, null, null, null, 'trained');
2996         if (!$dbman->field_exists($table, $field)) {
2997             $dbman->add_field($table, $field);
2998         }
2999         // Main savepoint reached.
3000         upgrade_main_savepoint(true, 2019041300.01);
3001     }
3003     if ($oldversion < 2019041800.01) {
3004         // STEP 1. For the existing and migrated self-conversations, set the type to the new MESSAGE_CONVERSATION_TYPE_SELF, update
3005         // the convhash and star them.
3006         $sql = "SELECT mcm.conversationid, mcm.userid, MAX(mcm.id) as maxid
3007                   FROM {message_conversation_members} mcm
3008             INNER JOIN {user} u ON mcm.userid = u.id
3009                  WHERE u.deleted = 0
3010               GROUP BY mcm.conversationid, mcm.userid
3011                 HAVING COUNT(*) > 1";
3012         $selfconversationsrs = $DB->get_recordset_sql($sql);
3013         $maxids = [];
3014         foreach ($selfconversationsrs as $selfconversation) {
3015             $DB->update_record('message_conversations',
3016                 ['id' => $selfconversation->conversationid,
3017                  'type' => \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF,
3018                  'convhash' => \core_message\helper::get_conversation_hash([$selfconversation->userid])
3019                 ]
3020             );
3022             // Star the existing self-conversation.
3023             $favouriterecord = new \stdClass();
3024             $favouriterecord->component = 'core_message';
3025             $favouriterecord->itemtype = 'message_conversations';
3026             $favouriterecord->itemid = $selfconversation->conversationid;
3027             $userctx = \context_user::instance($selfconversation->userid);
3028             $favouriterecord->contextid = $userctx->id;
3029             $favouriterecord->userid = $selfconversation->userid;
3030             if (!$DB->record_exists('favourite', (array)$favouriterecord)) {
3031                 $favouriterecord->timecreated = time();
3032                 $favouriterecord->timemodified = $favouriterecord->timecreated;
3033                 $DB->insert_record('favourite', $favouriterecord);
3034             }
3036             // Set the self-conversation member with maxid to remove it later.
3037             $maxids[] = $selfconversation->maxid;
3038         }
3039         $selfconversationsrs->close();
3041         // Remove the repeated member with the higher id for all the existing self-conversations.
3042         if (!empty($maxids)) {
3043             list($insql, $inparams) = $DB->get_in_or_equal($maxids);
3044             $DB->delete_records_select('message_conversation_members', "id $insql", $inparams);
3045         }
3047         // STEP 2. Migrate existing self-conversation relying on old message tables, setting the type to the new
3048         // MESSAGE_CONVERSATION_TYPE_SELF and the convhash to the proper one. Star them also.
3050         // On the messaging legacy tables, self-conversations are only present in the 'message_read' table, so we don't need to
3051         // check the content in the 'message' table.
3052         $sql = "SELECT mr.*
3053                   FROM {message_read} mr
3054             INNER JOIN {user} u ON mr.useridfrom = u.id
3055                  WHERE mr.useridfrom = mr.useridto AND mr.notification = 0 AND u.deleted = 0";
3056         $legacyselfmessagesrs = $DB->get_recordset_sql($sql);
3057         foreach ($legacyselfmessagesrs as $message) {
3058             // Get the self-conversation or create and star it if doesn't exist.
3059             $conditions = [
3060                 'type' => \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF,
3061                 'convhash' => \core_message\helper::get_conversation_hash([$message->useridfrom])
3062             ];
3063             $selfconversation = $DB->get_record('message_conversations', $conditions);
3064             if (empty($selfconversation)) {
3065                 // Create the self-conversation.
3066                 $selfconversation = new \stdClass();
3067                 $selfconversation->type = \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF;
3068                 $selfconversation->convhash = \core_message\helper::get_conversation_hash([$message->useridfrom]);
3069                 $selfconversation->enabled = 1;
3070                 $selfconversation->timecreated = time();
3071                 $selfconversation->timemodified = $selfconversation->timecreated;
3073                 $selfconversation->id = $DB->insert_record('message_conversations', $selfconversation);
3075                 // Add user to this self-conversation.
3076                 $member = new \stdClass();
3077                 $member->conversationid = $selfconversation->id;
3078                 $member->userid = $message->useridfrom;
3079                 $member->timecreated = time();
3081                 $member->id = $DB->insert_record('message_conversation_members', $member);
3083                 // Star the self-conversation.
3084                 $favouriterecord = new \stdClass();
3085                 $favouriterecord->component = 'core_message';
3086                 $favouriterecord->itemtype = 'message_conversations';
3087                 $favouriterecord->itemid = $selfconversation->id;
3088                 $userctx = \context_user::instance($message->useridfrom);
3089                 $favouriterecord->contextid = $userctx->id;
3090                 $favouriterecord->userid = $message->useridfrom;
3091                 if (!$DB->record_exists('favourite', (array)$favouriterecord)) {
3092                     $favouriterecord->timecreated = time();
3093                     $favouriterecord->timemodified = $favouriterecord->timecreated;
3094                     $DB->insert_record('favourite', $favouriterecord);
3095                 }
3096             }
3098             // Create the object we will be inserting into the database.
3099             $tabledata = new \stdClass();
3100             $tabledata->useridfrom = $message->useridfrom;
3101             $tabledata->conversationid = $selfconversation->id;
3102             $tabledata->subject = $message->subject;
3103             $tabledata->fullmessage = $message->fullmessage;
3104             $tabledata->fullmessageformat = $message->fullmessageformat ?? FORMAT_MOODLE;
3105             $tabledata->fullmessagehtml = $message->fullmessagehtml;
3106             $tabledata->smallmessage = $message->smallmessage;
3107             $tabledata->timecreated = $message->timecreated;
3109             $messageid = $DB->insert_record('messages', $tabledata);
3111             // Check if we need to mark this message as deleted (self-conversations add this information on the
3112             // timeuserfromdeleted field.
3113             if ($message->timeuserfromdeleted) {
3114                 $mua = new \stdClass();
3115                 $mua->userid = $message->useridfrom;
3116                 $mua->messageid = $messageid;
3117                 $mua->action = \core_message\api::MESSAGE_ACTION_DELETED;
3118                 $mua->timecreated = $message->timeuserfromdeleted;
3120                 $DB->insert_record('message_user_actions', $mua);
3121             }
3123             // Mark this message as read.
3124             $mua = new \stdClass();
3125             $mua->userid = $message->useridto;
3126             $mua->messageid = $messageid;
3127             $mua->action = \core_message\api::MESSAGE_ACTION_READ;
3128             $mua->timecreated = $message->timeread;
3130             $DB->insert_record('message_user_actions', $mua);
3132             // The self-conversation message has been migrated. Delete the record from the legacy table as soon as possible
3133             // to avoid migrate it twice.
3134             $DB->delete_records('message_read', ['id' => $message->id]);
3135         }
3136         $legacyselfmessagesrs->close();
3138         // Main savepoint reached.
3139         upgrade_main_savepoint(true, 2019041800.01);
3140     }
3142     if ($oldversion < 2019042200.01) {
3144         // Define table role_sortorder to be dropped.
3145         $table = new xmldb_table('role_sortorder');
3147         // Conditionally launch drop table for role_sortorder.
3148         if ($dbman->table_exists($table)) {
3149             $dbman->drop_table($table);
3150         }
3152         // Main savepoint reached.
3153         upgrade_main_savepoint(true, 2019042200.01);
3154     }
3156     if ($oldversion < 2019042200.02) {
3158         // Let's update all (old core) targets to their new (core_course) locations.
3159         $targets = [
3160             '\core\analytics\target\course_competencies' => '\core_course\analytics\target\course_competencies',
3161             '\core\analytics\target\course_completion' => '\core_course\analytics\target\course_completion',
3162             '\core\analytics\target\course_dropout' => '\core_course\analytics\target\course_dropout',
3163             '\core\analytics\target\course_gradetopass' => '\core_course\analytics\target\course_gradetopass',
3164             '\core\analytics\target\no_teaching' => '\core_course\analytics\target\no_teaching',
3165         ];
3167         foreach ($targets as $oldclass => $newclass) {
3168             $DB->set_field('analytics_models', 'target', $newclass, ['target' => $oldclass]);
3169         }
3171         // Main savepoint reached.
3172         upgrade_main_savepoint(true, 2019042200.02);
3173     }
3175     if ($oldversion < 2019042300.01) {
3176         $sql = "UPDATE {capabilities}
3177                    SET name = ?,
3178                        contextlevel = ?
3179                  WHERE name = ?";
3180         $DB->execute($sql, ['moodle/category:viewcourselist', CONTEXT_COURSECAT, 'moodle/course:browse']);
3182         $sql = "UPDATE {role_capabilities}
3183                    SET capability = ?
3184                  WHERE capability = ?";
3185         $DB->execute($sql, ['moodle/category:viewcourselist', 'moodle/course:browse']);
3187         // Main savepoint reached.
3188         upgrade_main_savepoint(true, 2019042300.01);
3189     }
3191     if ($oldversion < 2019042300.03) {
3193         // Add new customdata field to message table.
3194         $table = new xmldb_table('message');
3195         $field = new xmldb_field('customdata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'eventtype');
3197         // Conditionally launch add field output.
3198         if (!$dbman->field_exists($table, $field)) {
3199             $dbman->add_field($table, $field);
3200         }
3202         // Add new customdata field to notifications and messages table.
3203         $table = new xmldb_table('notifications');
3204         $field = new xmldb_field('customdata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'timecreated');
3206         // Conditionally launch add field output.
3207         if (!$dbman->field_exists($table, $field)) {
3208             $dbman->add_field($table, $field);
3209         }
3211         $table = new xmldb_table('messages');
3212         // Conditionally launch add field output.
3213         if (!$dbman->field_exists($table, $field)) {
3214             $dbman->add_field($table, $field);
3215         }
3217         // Main savepoint reached.
3218         upgrade_main_savepoint(true, 2019042300.03);
3219     }
3221     if ($oldversion < 2019042700.01) {
3223         // Define field firstanalysis to be added to analytics_used_analysables.
3224         $table = new xmldb_table('analytics_used_analysables');
3226         // Declaring it as null initially (although it is NOT NULL).
3227         $field = new xmldb_field('firstanalysis', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'analysableid');
3229         // Conditionally launch add field firstanalysis.
3230         if (!$dbman->field_exists($table, $field)) {
3231             $dbman->add_field($table, $field);
3233             // Set existing values to the current timeanalysed value.
3234             $recordset = $DB->get_recordset('analytics_used_analysables');
3235             foreach ($recordset as $record) {
3236                 $record->firstanalysis = $record->timeanalysed;
3237                 $DB->update_record('analytics_used_analysables', $record);
3238             }
3239             $recordset->close();
3241             // Now make the field 'NOT NULL'.
3242             $field = new xmldb_field('firstanalysis', XMLDB_TYPE_INTEGER, '10',
3243                 null, XMLDB_NOTNULL, null, null, 'analysableid');
3244             $dbman->change_field_notnull($table, $field);
3245         }
3247         // Main savepoint reached.
3248         upgrade_main_savepoint(true, 2019042700.01);
3249     }
3251     if ($oldversion < 2019050300.01) {
3252         // Delete all stale favourite records which were left behind when a course was deleted.
3253         $params = ['component' => 'core_message', 'itemtype' => 'message_conversations'];
3254         $sql = "SELECT fav.id as id
3255                   FROM {favourite} fav
3256              LEFT JOIN {context} ctx ON (ctx.id = fav.contextid)
3257                  WHERE fav.component = :component
3258                        AND fav.itemtype = :itemtype
3259                        AND ctx.id IS NULL";
3261         if ($records = $DB->get_fieldset_sql($sql, $params)) {
3262             // Just for safety, delete by chunks.
3263             $chunks = array_chunk($records, 1000);
3264             foreach ($chunks as $chunk) {
3265                 list($insql, $inparams) = $DB->get_in_or_equal($chunk);
3266                 $DB->delete_records_select('favourite', "id $insql", $inparams);
3267             }
3268         }
3270         upgrade_main_savepoint(true, 2019050300.01);
3271     }
3273     if ($oldversion < 2019050600.00) {
3275         // Define field apiversion to be added to badge_backpack.
3276         $table = new xmldb_table('badge_backpack');
3277         $field = new xmldb_field('apiversion', XMLDB_TYPE_CHAR, '12', null, XMLDB_NOTNULL, null, '1.0', 'password');
3279         // Conditionally launch add field apiversion.
3280         if (!$dbman->field_exists($table, $field)) {
3281             $dbman->add_field($table, $field);
3282         }
3284         // Define table badge_external_backpack to be created.
3285         $table = new xmldb_table('badge_external_backpack');
3287         // Adding fields to table badge_external_backpack.
3288         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3289         $table->add_field('backpackapiurl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
3290         $table->add_field('backpackweburl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
3291         $table->add_field('apiversion', XMLDB_TYPE_CHAR, '12', null, XMLDB_NOTNULL, null, '1.0');
3292         $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
3293         $table->add_field('password', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3295         // Adding keys to table badge_external_backpack.
3296         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
3297         $table->add_key('backpackapiurlkey', XMLDB_KEY_UNIQUE, ['backpackapiurl']);
3298         $table->add_key('backpackweburlkey', XMLDB_KEY_UNIQUE, ['backpackweburl']);
3300         // Conditionally launch create table for badge_external_backpack.
3301         if (!$dbman->table_exists($table)) {
3302             $dbman->create_table($table);
3303         }
3305         // Define field entityid to be added to badge_external.
3306         $table = new xmldb_table('badge_external');
3307         $field = new xmldb_field('entityid', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'collectionid');
3309         // Conditionally launch add field entityid.
3310         if (!$dbman->field_exists($table, $field)) {
3311             $dbman->add_field($table, $field);
3312         }
3314         // Define table badge_external_identifier to be created.
3315         $table = new xmldb_table('badge_external_identifier');
3317         // Adding fields to table badge_external_identifier.
3318         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3319         $table->add_field('sitebackpackid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
3320         $table->add_field('internalid', XMLDB_TYPE_CHAR, '128', null, XMLDB_NOTNULL, null, null);
3321         $table->add_field('externalid', XMLDB_TYPE_CHAR, '128', null, XMLDB_NOTNULL, null, null);
3322         $table->add_field('type', XMLDB_TYPE_CHAR, '16', null, XMLDB_NOTNULL, null, null);
3324         // Adding keys to table badge_external_identifier.
3325         $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
3326         $table->add_key('fk_backpackid', XMLDB_KEY_FOREIGN, ['sitebackpackid'], 'badge_backpack', ['id']);
3327         $table->add_key('backpack-internal-external', XMLDB_KEY_UNIQUE, ['sitebackpackid', 'internalid', 'externalid', 'type']);
3329         // Conditionally launch create table for badge_external_identifier.
3330         if (!$dbman->table_exists($table)) {
3331             $dbman->create_table($table);
3332         }
3334         // Define field externalbackpackid to be added to badge_backpack.
3335         $table = new xmldb_table('badge_backpack');
3336         $field = new xmldb_field('externalbackpackid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'password');
3338         // Conditionally launch add field externalbackpackid.
3339         if (!$dbman->field_exists($table, $field)) {
3340             $dbman->add_field($table, $field);
3341         }
3343         // Define key externalbackpack (foreign) to be added to badge_backpack.
3344         $key = new xmldb_key('externalbackpack', XMLDB_KEY_FOREIGN, ['externalbackpackid'], 'badge_external_backpack', ['id']);
3346         // Launch add key externalbackpack.
3347         $dbman->add_key($table, $key);
3349         $field = new xmldb_field('apiversion');
3351         // Conditionally launch drop field apiversion.
3352         if ($dbman->field_exists($table, $field)) {
3353             $dbman->drop_field($table, $field);
3354         }
3356         $field = new xmldb_field('backpackurl');
3358         // Conditionally launch drop field backpackurl.
3359         if ($dbman->field_exists($table, $field)) {
3360             $dbman->drop_field($table, $field);
3361         }
3363         // Add default backpacks.
3364         require_once($CFG->libdir.'/badgeslib.php'); // Core Upgrade-related functions for badges only.
3365         badges_install_default_backpacks();
3367         // Main savepoint reached.
3368         upgrade_main_savepoint(true, 2019050600.00);
3369     }
3371     if ($oldversion < 2019051300.01) {
3372         $DB->set_field('analytics_models', 'enabled', '1', ['target' => '\core_user\analytics\target\upcoming_activities_due']);
3374         // Main savepoint reached.
3375         upgrade_main_savepoint(true, 2019051300.01);
3376     }
3378     // Automatically generated Moodle v3.7.0 release upgrade line.
3379     // Put any upgrade step following this.
3381     if ($oldversion < 2019060600.02) {
3382         // Renaming 'opentogoogle' config to 'opentowebcrawlers'.
3383         $opentogooglevalue = get_config('core', 'opentogoogle');
3385         // Move the value over if it was previously configured.
3386         if ($opentogooglevalue !== false) {
3387             set_config('opentowebcrawlers', $opentogooglevalue);
3388         }
3390         // Remove the now unused value.
3391         unset_config('opentogoogle');
3393         // Main savepoint reached.
3394         upgrade_main_savepoint(true, 2019060600.02);
3395     }
3397     if ($oldversion < 2019062900.00) {
3398         // Debugsmtp is now only available via config.php.
3399         $DB->delete_records('config', array('name' => 'debugsmtp'));
3401         // Main savepoint reached.
3402         upgrade_main_savepoint(true, 2019062900.00);
3403     }
3405     if ($oldversion < 2019070400.01) {
3407         $basecolors = ['#81ecec', '#74b9ff', '#a29bfe', '#dfe6e9', '#00b894',
3408             '#0984e3', '#b2bec3', '#fdcb6e', '#fd79a8', '#6c5ce7'];
3410         $colornr = 1;
3411         foreach ($basecolors as $color) {
3412             set_config('coursecolor' .  $colornr, $color, 'core_admin');
3413             $colornr++;
3414         }
3416         upgrade_main_savepoint(true, 2019070400.01);
3417     }
3419     return true;