MDL-27171 messages: implement new syntax in messages.php and update processing
[moodle.git] / lib / db / upgradelib.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * Upgrade helper functions
20  *
21  * This file is used for special upgrade functions - for example groups and gradebook.
22  * These functions must use SQL and database related functions only- no other Moodle API,
23  * because it might depend on db structures that are not yet present during upgrade.
24  * (Do not use functions from accesslib.php, grades classes or group functions at all!)
25  *
26  * @package    core
27  * @subpackage admin
28  * @copyright  2007 Petr Skoda (http://skodak.org)
29  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30  */
32 defined('MOODLE_INTERNAL') || die();
34 function upgrade_fix_category_depths() {
35     global $CFG, $DB;
37     // first fix incorrect parents
38     $sql = "SELECT c.id
39               FROM {course_categories} c
40              WHERE c.parent > 0 AND c.parent NOT IN (SELECT pc.id FROM {course_categories} pc)";
41     $rs = $DB->get_recordset_sql($sql);
42     foreach ($rs as $cat) {
43         $cat->depth  = 1;
44         $cat->path   = '/'.$cat->id;
45         $cat->parent = 0;
46         $DB->update_record('course_categories', $cat);
47     }
48     $rs->close();
50     // now add path and depth to top level categories
51     $sql = "UPDATE {course_categories}
52                SET depth = 1, path = ".$DB->sql_concat("'/'", "id")."
53              WHERE parent = 0";
54     $DB->execute($sql);
56     // now fix all other levels - slow but works in all supported dbs
57     $parentdepth = 1;
58     while ($DB->record_exists('course_categories', array('depth'=>0))) {
59         $sql = "SELECT c.id, pc.path
60                   FROM {course_categories} c, {course_categories} pc
61                  WHERE c.parent=pc.id AND c.depth=0 AND pc.depth=?";
62         $rs = $DB->get_recordset_sql($sql, array($parentdepth));
63         foreach ($rs as $cat) {
64             $cat->depth = $parentdepth+1;
65             $cat->path  = $cat->path.'/'.$cat->id;
66             $DB->update_record('course_categories', $cat);
67         }
68         $rs->close();
69         $parentdepth++;
70         if ($parentdepth > 100) {
71             //something must have gone wrong - nobody can have more than 100 levels of categories, right?
72             debugging('Unknown error fixing category depths');
73             break;
74         }
75     }
76 }
78 /**
79  * Moves all course files except the moddata to new file storage
80  *
81  * Unfortunately this function uses core file related functions - it might be necessary to tweak it if something changes there :-(
82  */
83 function upgrade_migrate_files_courses() {
84     global $DB, $CFG;
85     require_once($CFG->libdir.'/filelib.php');
87     set_config('upgradenewfilemirgation', 1);
89     $count = $DB->count_records('course');
90     $pbar = new progress_bar('migratecoursefiles', 500, true);
92     $rs = $DB->get_recordset('course');
93     $i = 0;
94     foreach ($rs as $course) {
95         $i++;
96         upgrade_set_timeout(60*5); // set up timeout, may also abort execution
97         $context = get_context_instance(CONTEXT_COURSE, $course->id);
98         upgrade_migrate_files_course($context, '/', true);
99         $pbar->update($i, $count, "Migrated course files - course $i/$count.");
100     }
101     $rs->close();
103     return true;
106 /**
107  * Moodle 2.0dev was using xx/xx/xx file pool directory structure, this migrates the existing files to xx/xx.
108  * This will not be executed in production upgrades...
109  * @return void
110  */
111 function upgrade_simplify_overkill_pool_structure() {
112     global $CFG, $OUTPUT;
114     if (isset($CFG->upgradenewfilemirgation)) {
115         // newer upgrade, directory structure is in the form xx/xx already
116         unset_config('upgradenewfilemirgation');
117         return;
118     }
120     $filedir = $CFG->dataroot.'/filedir'; // hardcoded hack, do not use elsewhere!!
122     echo $OUTPUT->notification("Changing file pool directory structure, this may take a while...", 'notifysuccess');
124     $dir_l1 = new DirectoryIterator($filedir);
125     foreach ($dir_l1 as $d1) {
126         if ($d1->isDot() or $d1->isLink() or !$d1->isDir()) {
127             continue;
128         }
129         $name1 = $d1->getFilename();
130         if (strlen($name1) != 2) {
131             continue; //weird
132         }
133         $dir_l2 = new DirectoryIterator("$filedir/$name1");
134         foreach ($dir_l2 as $d2) {
135             if ($d2->isDot() or $d2->isLink() or !$d2->isDir()) {
136                 continue;
137             }
138             $name2 = $d2->getFilename();
139             if (strlen($name2) != 2) {
140                 continue; //weird
141             }
142             $dir_l3 = new DirectoryIterator("$filedir/$name1/$name2");
143             foreach ($dir_l3 as $d3) {
144                 if ($d3->isDot() or $d3->isLink() or !$d3->isDir()) {
145                     continue;
146                 }
147                 $name3 = $d3->getFilename();
148                 if (strlen($name3) != 2) {
149                     continue; //weird
150                 }
151                 $dir_l4 = new DirectoryIterator("$filedir/$name1/$name2/$name3");
152                 foreach ($dir_l4 as $d4) {
153                     if (!$d4->isFile()) {
154                         continue; //. or ..
155                     }
156                     upgrade_set_timeout(60*5); // set up timeout, may also abort execution
157                     $newfile = "$filedir/$name1/$name2/".$d4->getFilename();
158                     $oldfile = "$filedir/$name1/$name2/$name3/".$d4->getFilename();
159                     if (!file_exists($newfile)) {
160                         rename($oldfile, $newfile);
161                     }
162                 }
163                 unset($d4);
164                 unset($dir_l4);
165                 rmdir("$filedir/$name1/$name2/$name3");
166             }
167             unset($d3);
168             unset($dir_l3); // release file handles
169         }
170         unset($d2);
171         unset($dir_l2); // release file handles
172     }
175 /**
176  * Internal function - do not use directly
177  */
178 function upgrade_migrate_user_icons() {
179     global $CFG, $OUTPUT, $DB;
181     $fs = get_file_storage();
183     $icon = array('component'=>'user', 'filearea'=>'icon', 'itemid'=>0, 'filepath'=>'/');
185     $count = $DB->count_records('user', array('picture'=>1, 'deleted'=>0));
186     $pbar = new progress_bar('migrateusericons', 500, true);
188     $rs = $DB->get_recordset('user', array('picture'=>1, 'deleted'=>0), 'id ASC', 'id, picture');
189     $i = 0;
190     foreach ($rs as $user) {
191         $i++;
192         upgrade_set_timeout(60); /// Give upgrade at least 60 more seconds
193         $pbar->update($i, $count, "Migrated user icons $i/$count.");
195         $context = get_context_instance(CONTEXT_USER, $user->id);
197         if ($fs->file_exists($context->id, 'user', 'icon', 0, '/', 'f1.jpg')) {
198             // already converted!
199             continue;
200         }
202         $level1 = floor($user->id / 1000) * 1000;
203         $userdir = "$CFG->dataroot/user/$level1/$user->id";
204         if (!file_exists("$userdir/f1.jpg") or !file_exists("$userdir/f2.jpg")) {
205             $userdir = "$CFG->dataroot/users/$user->id";
206             if (!file_exists("$userdir/f1.jpg") or !file_exists("$userdir/f2.jpg")) {
207                 // no image found, sorry
208                 $user->picture = 0;
209                 $DB->update_record('user', $user);
210                 continue;
211             }
212         }
214         $icon['contextid'] = $context->id;
215         $icon['filename']  = 'f1.jpg';
216         $fs->create_file_from_pathname($icon, "$userdir/f1.jpg");
217         $icon['filename']  = 'f2.jpg';
218         $fs->create_file_from_pathname($icon, "$userdir/f2.jpg");
219     }
220     $rs->close();
222     // purge all old user image dirs
223     remove_dir("$CFG->dataroot/user");
224     remove_dir("$CFG->dataroot/users");
227 /**
228  * Internal function - do not use directly
229  */
230 function upgrade_migrate_group_icons() {
231     global $CFG, $OUTPUT, $DB;
233     $fs = get_file_storage();
235     $icon = array('component'=>'group', 'filearea'=>'icon', 'filepath'=>'/');
237     $count = $DB->count_records('groups', array('picture'=>1));
238     $pbar = new progress_bar('migrategroupfiles', 500, true);
240     $rs = $DB->get_recordset('groups', array('picture'=>1), 'courseid ASC', 'id, picture, courseid');
241     $i = 0;
242     foreach ($rs as $group) {
243         $i++;
244         upgrade_set_timeout(60); /// Give upgrade at least 60 more seconds
245         $pbar->update($i, $count, "Migrated group icons  $i/$count.");
247         if (!$context = get_context_instance(CONTEXT_COURSE, $group->courseid)) {
248             debugging('Invalid group record (id=' . $group->id . ') found.');
249             continue;
250         }
252         if ($fs->file_exists($context->id, 'group', 'icon', $group->id, '/', 'f1.jpg')) {
253             // already converted!
254             continue;
255         }
257         $groupdir = "$CFG->dataroot/groups/$group->id";
258         if (!file_exists("$groupdir/f1.jpg") or !file_exists("$groupdir/f2.jpg")) {
259             // no image found, sorry
260             $group->picture = 0;
261             $DB->update_record('groups', $group);
262             continue;
263         }
265         $icon['contextid'] = $context->id;
266         $icon['itemid']    = $group->id;
267         $icon['filename']  = 'f1.jpg';
268         $fs->create_file_from_pathname($icon, "$groupdir/f1.jpg");
269         $icon['filename']  = 'f2.jpg';
270         $fs->create_file_from_pathname($icon, "$groupdir/f2.jpg");
271     }
272     $rs->close();
274     // purge all old group image dirs
275     remove_dir("$CFG->dataroot/groups");
278 /**
279  * Internal function - do not use directly
280  */
281 function upgrade_migrate_files_course($context, $path, $delete) {
282     global $CFG, $OUTPUT;
284     $fullpathname = $CFG->dataroot.'/'.$context->instanceid.$path;
285     if (!file_exists($fullpathname)) {
286         return;
287     }
288     $items = new DirectoryIterator($fullpathname);
289     $fs = get_file_storage();
291     $textlib = textlib_get_instance();
293     foreach ($items as $item) {
294         if ($item->isDot()) {
295             continue;
296         }
298         if ($item->isLink()) {
299             // do not delete symbolic links or its children
300             $delete_this = false;
301         } else {
302             $delete_this = $delete;
303         }
305         if (strpos($path, '/backupdata/') === 0) {
306             $component = 'backup';
307             $filearea  = 'course';
308             $filepath  = substr($path, strlen('/backupdata'));
309         } else {
310             $component = 'course';
311             $filearea  = 'legacy';
312             $filepath  = $path;
313         }
315         if ($item->isFile()) {
316             if (!$item->isReadable()) {
317                 echo $OUTPUT->notification(" File not readable, skipping: ".$fullpathname.$item->getFilename());
318                 continue;
319             }
321             $filepath = clean_param($filepath, PARAM_PATH);
322             $filename = clean_param($item->getFilename(), PARAM_FILE);
324             if ($filename === '') {
325                 //unsupported chars, sorry
326                 continue;
327             }
329             if ($textlib->strlen($filepath) > 255) {
330                 echo $OUTPUT->notification(" File path longer than 255 chars, skipping: ".$fullpathname.$item->getFilename());
331                 continue;
332             }
334             if (!$fs->file_exists($context->id, $component, $filearea, '0', $filepath, $filename)) {
335                 $file_record = array('contextid'=>$context->id, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>0, 'filepath'=>$filepath, 'filename'=>$filename,
336                                      'timecreated'=>$item->getCTime(), 'timemodified'=>$item->getMTime());
337                 if ($fs->create_file_from_pathname($file_record, $fullpathname.$item->getFilename())) {
338                     if ($delete_this) {
339                         @unlink($fullpathname.$item->getFilename());
340                     }
341                 }
342             }
344         } else {
345             if ($path == '/' and $item->getFilename() == 'moddata') {
346                 continue; // modules are responsible
347             }
349             $dirname = clean_param($item->getFilename(), PARAM_PATH);
350             if ($dirname === '') {
351                 //unsupported chars, sorry
352                 continue;
353             }
354             $filepath = ($filepath.$dirname.'/');
355             if ($filepath !== '/backupdata/') {
356                 $fs->create_directory($context->id, $component, $filearea, 0, $filepath);
357             }
359             //migrate recursively all subdirectories
360             upgrade_migrate_files_course($context, $path.$item->getFilename().'/', $delete_this);
361             if ($delete_this) {
362                 // delete dir if empty
363                 @rmdir($fullpathname.$item->getFilename());
364             }
365         }
366     }
367     unset($items); //release file handles
370 /**
371  * Moves all block attachments
372  *
373  * Unfortunately this function uses core file related functions - it might be necessary to tweak it if something changes there :-(
374  */
375 function upgrade_migrate_files_blog() {
376     global $DB, $CFG, $OUTPUT;
378     $fs = get_file_storage();
380     $count = $DB->count_records_select('post', "module='blog' AND attachment IS NOT NULL AND attachment <> '1'");
382     $rs = $DB->get_recordset_select('post', "module='blog' AND attachment IS NOT NULL AND attachment <> '1'");
384     if ($rs->valid()) {
386         upgrade_set_timeout(60*20); // set up timeout, may also abort execution
388         $pbar = new progress_bar('migrateblogfiles', 500, true);
390         $i = 0;
391         foreach ($rs as $entry) {
392             $i++;
393             $pathname = "$CFG->dataroot/blog/attachments/$entry->id/$entry->attachment";
394             if (!file_exists($pathname)) {
395                 $entry->attachment = NULL;
396                 $DB->update_record('post', $entry);
397                 continue;
398             }
400             $filename = clean_param($entry->attachment, PARAM_FILE);
401             if ($filename === '') {
402                 // weird file name, ignore it
403                 $entry->attachment = NULL;
404                 $DB->update_record('post', $entry);
405                 continue;
406             }
408             if (!is_readable($pathname)) {
409                 echo $OUTPUT->notification(" File not readable, skipping: ".$pathname);
410                 continue;
411             }
413             if (!$fs->file_exists(SYSCONTEXTID, 'blog', 'attachment', $entry->id, '/', $filename)) {
414                 $file_record = array('contextid'=>SYSCONTEXTID, 'component'=>'blog', 'filearea'=>'attachment', 'itemid'=>$entry->id, 'filepath'=>'/', 'filename'=>$filename,
415                                      'timecreated'=>filectime($pathname), 'timemodified'=>filemtime($pathname), 'userid'=>$entry->userid);
416                 $fs->create_file_from_pathname($file_record, $pathname);
417             }
418             @unlink($pathname);
419             @rmdir("$CFG->dataroot/blog/attachments/$entry->id/");
421             $entry->attachment = 1; // file name not needed there anymore
422             $DB->update_record('post', $entry);
423             $pbar->update($i, $count, "Migrated blog attachments - $i/$count.");
424         }
425     }
426     $rs->close();
428     @rmdir("$CFG->dataroot/blog/attachments/");
429     @rmdir("$CFG->dataroot/blog/");
432 /**
433  * This function will fix the status of the localhost/all records in the mnet_host table
434  * checking they exist and adding them if missing + redefine CFG->mnet_localhost_id  and
435  * CFG->mnet_all_hosts_id if needed + update all the users having non-existent mnethostid
436  * to correct CFG->mnet_localhost_id
437  *
438  * Implemented because, at some point, specially in old installations upgraded along
439  * multiple versions, sometimes the stuff above has ended being inconsistent, causing
440  * problems here and there (noticeably in backup/restore). MDL-16879
441  */
442 function upgrade_fix_incorrect_mnethostids() {
444     global $CFG, $DB;
446 /// Get current $CFG/mnet_host records
447     $old_mnet_localhost_id = !empty($CFG->mnet_localhost_id) ? $CFG->mnet_localhost_id : 0;
448     $old_mnet_all_hosts_id = !empty($CFG->mnet_all_hosts_id) ? $CFG->mnet_all_hosts_id : 0;
450     $current_mnet_localhost_host = $DB->get_record('mnet_host', array('wwwroot' => $CFG->wwwroot)); /// By wwwroot
451     $current_mnet_all_hosts_host = $DB->get_record_select('mnet_host', $DB->sql_isempty('mnet_host', 'wwwroot', false, false)); /// By empty wwwroot
453     if (!$moodleapplicationid = $DB->get_field('mnet_application', 'id', array('name' => 'moodle'))) {
454         $m = (object)array(
455             'name'              => 'moodle',
456             'display_name'      => 'Moodle',
457             'xmlrpc_server_url' => '/mnet/xmlrpc/server.php',
458             'sso_land_url'      => '/auth/mnet/land.php',
459             'sso_jump_url'      => '/auth/mnet/jump.php',
460         );
461         $moodleapplicationid = $DB->insert_record('mnet_application', $m);
462     }
464 /// Create localhost_host if necessary (pretty improbable but better to be 100% in the safe side)
465 /// Code stolen from mnet_environment->init
466     if (!$current_mnet_localhost_host) {
467         $current_mnet_localhost_host                     = new stdClass();
468         $current_mnet_localhost_host->wwwroot            = $CFG->wwwroot;
469         $current_mnet_localhost_host->ip_address         = '';
470         $current_mnet_localhost_host->public_key         = '';
471         $current_mnet_localhost_host->public_key_expires = 0;
472         $current_mnet_localhost_host->last_connect_time  = 0;
473         $current_mnet_localhost_host->last_log_id        = 0;
474         $current_mnet_localhost_host->deleted            = 0;
475         $current_mnet_localhost_host->name               = '';
476         $current_mnet_localhost_host->applicationid      = $moodleapplicationid;
477     /// Get the ip of the server
478         if (empty($_SERVER['SERVER_ADDR'])) {
479         /// SERVER_ADDR is only returned by Apache-like webservers
480             $count = preg_match("@^(?:http[s]?://)?([A-Z0-9\-\.]+).*@i", $current_mnet_localhost_host->wwwroot, $matches);
481             $my_hostname = $count > 0 ? $matches[1] : false;
482             $my_ip       = gethostbyname($my_hostname);  // Returns unmodified hostname on failure. DOH!
483             if ($my_ip == $my_hostname) {
484                 $current_mnet_localhost_host->ip_address = 'UNKNOWN';
485             } else {
486                 $current_mnet_localhost_host->ip_address = $my_ip;
487             }
488         } else {
489             $current_mnet_localhost_host->ip_address = $_SERVER['SERVER_ADDR'];
490         }
491         $current_mnet_localhost_host->id = $DB->insert_record('mnet_host', $current_mnet_localhost_host, true);
492     }
494 /// Create all_hosts_host if necessary (pretty improbable but better to be 100% in the safe side)
495 /// Code stolen from mnet_environment->init
496     if (!$current_mnet_all_hosts_host) {
497         $current_mnet_all_hosts_host                     = new stdClass();
498         $current_mnet_all_hosts_host->wwwroot            = '';
499         $current_mnet_all_hosts_host->ip_address         = '';
500         $current_mnet_all_hosts_host->public_key         = '';
501         $current_mnet_all_hosts_host->public_key_expires = 0;
502         $current_mnet_all_hosts_host->last_connect_time  = 0;
503         $current_mnet_all_hosts_host->last_log_id        = 0;
504         $current_mnet_all_hosts_host->deleted            = 0;
505         $current_mnet_all_hosts_host->name               = 'All Hosts';
506         $current_mnet_all_hosts_host->applicationid      = $moodleapplicationid;
507         $current_mnet_all_hosts_host->id                 = $DB->insert_record('mnet_host', $current_mnet_all_hosts_host, true);
508     }
510 /// Compare old_mnet_localhost_id and current_mnet_localhost_host
512     if ($old_mnet_localhost_id != $current_mnet_localhost_host->id) { /// Different = problems
513     /// Update $CFG->mnet_localhost_id to correct value
514         set_config('mnet_localhost_id', $current_mnet_localhost_host->id);
516     /// Delete $old_mnet_localhost_id if exists (users will be assigned to new one below)
517         $DB->delete_records('mnet_host', array('id' => $old_mnet_localhost_id));
518     }
520 /// Compare old_mnet_all_hosts_id and current_mnet_all_hosts_host
522     if ($old_mnet_all_hosts_id != $current_mnet_all_hosts_host->id) { /// Different = problems
523     /// Update $CFG->mnet_localhost_id to correct value
524         set_config('mnet_all_hosts_id', $current_mnet_all_hosts_host->id);
526     /// Delete $old_mnet_all_hosts_id if exists
527         $DB->delete_records('mnet_host', array('id' => $old_mnet_all_hosts_id));
528     }
530 /// Finally, update all the incorrect user->mnethostid to the correct CFG->mnet_localhost_id, preventing UIX dupes
531     $hosts = $DB->get_records_menu('mnet_host', null, '', 'id, id AS id2');
532     list($in_sql, $in_params) = $DB->get_in_or_equal($hosts, SQL_PARAMS_QM, null, false);
534     $sql = "SELECT id
535             FROM {user} u1
536             WHERE u1.mnethostid $in_sql
537               AND NOT EXISTS (
538                   SELECT 'x'
539                     FROM {user} u2
540                    WHERE u2.username = u1.username
541                      AND u2.mnethostid = ?)";
543     $params = array_merge($in_params, array($current_mnet_localhost_host->id));
545     $rs = $DB->get_recordset_sql($sql, $params);
546     foreach ($rs as $rec) {
547         $DB->set_field('user', 'mnethostid', $current_mnet_localhost_host->id, array('id' => $rec->id));
548         upgrade_set_timeout(60); /// Give upgrade at least 60 more seconds
549     }
550     $rs->close();
552     // fix up any host records that have incorrect ids
553     $DB->set_field_select('mnet_host', 'applicationid', $moodleapplicationid, 'id = ? or id = ?', array($current_mnet_localhost_host->id, $current_mnet_all_hosts_host->id));
557 /**
558  * This function is used as part of the great navigation upgrade of 20090828
559  * It is used to clean up contexts that are unique to a blocks that are about
560  * to be removed.
561  *
562  *
563  * Look at {@link blocklib.php::blocks_delete_instance()} the function from
564  * which I based this code. It is important to mention one very important fact
565  * before doing this I checked that the blocks did not override the
566  * {@link block_base::instance_delete()} method. Should this function ever
567  * be repeated check this again
568  *
569  * @link lib/db/upgrade.php
570  *
571  * @since navigation upgrade 20090828
572  * @param array $contextidarray An array of block instance context ids
573  * @return void
574  */
575 function upgrade_cleanup_unwanted_block_contexts($contextidarray) {
576     global $DB;
578     if (!is_array($contextidarray) || count($contextidarray)===0) {
579         // Ummmm no instances?
580         return;
581     }
583     $contextidstring = join(',', $contextidarray);
585     $blockcontexts = $DB->get_recordset_select('context', 'contextlevel = '.CONTEXT_BLOCK.' AND id IN ('.$contextidstring.')', array(), '', 'id, contextlevel');
586     $blockcontextids = array();
587     foreach ($blockcontexts as $blockcontext) {
588         $blockcontextids[] = $blockcontext->id;
589     }
591     if (count($blockcontextids)===0) {
592         // None of the instances have unique contexts
593         return;
594     }
596     $blockcontextidsstring = join(',', $blockcontextids);
598     $DB->delete_records_select('role_assignments', 'contextid IN ('.$blockcontextidsstring.')');
599     $DB->delete_records_select('role_capabilities', 'contextid IN ('.$blockcontextidsstring.')');
600     $DB->delete_records_select('role_names', 'contextid IN ('.$blockcontextidsstring.')');
601     $DB->delete_records_select('context', 'id IN ('.$blockcontextidsstring.')');
604 /**
605  * This function is used to establish the automated backup settings using the
606  * original scheduled backup settings.
607  *
608  * @since 2010111000
609  */
610 function update_fix_automated_backup_config() {
611     $mappings = array(
612         // Old setting      => new setting
613         'backup_sche_active'            => 'backup_auto_active',
614         'backup_sche_hour'              => 'backup_auto_hour',
615         'backup_sche_minute'            => 'backup_auto_minute',
616         'backup_sche_destination'       => 'backup_auto_destination',
617         'backup_sche_keep'              => 'backup_auto_keep',
618         'backup_sche_userfiles'         => 'backup_auto_user_files',
619         'backup_sche_modules'           => 'backup_auto_activities',
620         'backup_sche_logs'              => 'backup_auto_logs',
621         'backup_sche_messages'          => 'backup_auto_messages',
622         'backup_sche_blocks'            => 'backup_auto_blocks',
623         'backup_sche_weekdays'          => 'backup_auto_weekdays',
624         'backup_sche_users'             => 'backup_auto_users',
625         'backup_sche_blogs'             => 'backup_auto_blogs',
626         'backup_sche_coursefiles'       => null,
627         'backup_sche_sitefiles'         => null,
628         'backup_sche_withuserdata'      => null,
629         'backup_sche_metacourse'        => null,
630         'backup_sche_running'           => null,
631     );
633     $oldconfig = get_config('backup');
634     foreach ($mappings as $oldsetting=>$newsetting) {
635         if (!isset($oldconfig->$oldsetting)) {
636             continue;
637         }
638         if ($newsetting !== null) {
639             $oldvalue = $oldconfig->$oldsetting;
640             set_config($newsetting, $oldvalue, 'backup');
641         }
642         unset_config($oldsetting, 'backup');
643     }
645     unset_config('backup_sche_gradebook_history');
646     unset_config('disablescheduleddbackups');
649 /**
650  * This function is used to set default messaging preferences when the new
651  * admin-level messaging defaults settings have been introduced.
652  */
653 function upgrade_populate_default_messaging_prefs() {
654     global $DB;
656     $providers = $DB->get_records('message_providers');
657     $processors = $DB->get_records('message_processors');
658     $defaultpreferences = $DB->get_records_menu('config_plugins', array('plugin'=>'message'), '', 'name,value');
660     $transaction = $DB->start_delegated_transaction();
662     $setting = new stdClass();
663     $setting->plugin = 'message';
665     foreach ($providers as $provider) {
666         $componentproviderbase = $provider->component.'_'.$provider->name;
667         // set MESSAGE_PERMITTED to all combinations of message types
668         // (providers) and outputs (processors)
669         foreach ($processors as $processor) {
670             $preferencename = $processor->name.'_provider_'.$componentproviderbase.'_permitted';
671             if (!array_key_exists($preferencename, $defaultpreferences)) {
672                 $setting->name = $preferencename;
673                 $setting->value = 'permitted';
674                 $DB->insert_record('config_plugins', $setting);
675             }
676         }
677         // for email output we also have to set MESSAGE_DEFAULT_OFFLINE + MESSAGE_DEFAULT_ONLINE
678         foreach(array('loggedin', 'loggedoff') as $state) {
679             $preferencename = 'message_provider_'.$componentproviderbase.'_'.$state;
680             if (!array_key_exists($preferencename, $defaultpreferences)) {
681                 $setting->name = $preferencename;
682                 $setting->value = 'email';
683                 // except instant message where default for popup should be
684                 // MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF and for email
685                 // MESSAGE_DEFAULT_LOGGEDOFF.
686                 if ($componentproviderbase == 'moodle_instantmessage') {
687                     if  ($state == 'loggedoff') {
688                         $setting->value = 'email,popup';
689                     } else {
690                         $setting->value = 'popup';
691                     }
692                 }
693                 $DB->insert_record('config_plugins', $setting);
694             }
695         }
696     }
697     $transaction->allow_commit();