upgrade.php 35.4 KB
Newer Older
1
2
<?php
/**
Francois Marier's avatar
Francois Marier committed
3
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
4
 * Copyright (C) 2006-2008 Catalyst IT Ltd (http://www.catalyst.net.nz)
5
 *
Francois Marier's avatar
Francois Marier committed
6
7
8
9
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
10
 *
Francois Marier's avatar
Francois Marier committed
11
12
13
14
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
15
 *
Francois Marier's avatar
Francois Marier committed
16
17
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19
 *
 * @package    mahara
20
 * @subpackage core
21
 * @author     Catalyst IT Ltd
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
23
 * @copyright  (C) 2006-2008 Catalyst IT Ltd http://catalyst.net.nz
24
25
26
27
28
29
30
31
 *
 */

defined('INTERNAL') || die();

/**
 * Class to use for installation exceptions
 */
32
class InstallationException extends SystemException {}
33

34
require_once('ddl.php');
35
36

/**
37
38
39
40
41
 * This function checks core and plugins for which need to be upgraded/installed
 *
 * @param string $name The name of the plugin to check. If no name is specified,
 *                     all plugins are checked.
 * @return array of objects
42
 */
43
function check_upgrades($name=null) {
44

45
46
47
48
    $pluginstocheck = plugin_types();

    $toupgrade = array();
    $installing = false;
49
    $disablelogin = false;
50
51

    require('version.php');
52
53
54
    if (isset($config->disablelogin) && !empty($config->disablelogin)) {
        $disablelogin = true;
    }
55
56
57
58
    // check core first...
    if (empty($name) || $name == 'core') {
        try {
            $coreversion = get_config('version');
Elliot Pahl's avatar
Elliot Pahl committed
59
        }
60
61
62
63
        catch (Exception $e) {
            $coreversion = 0;
        }
        if (empty($coreversion)) {
64
65
66
67
68
69
70
            if (is_mysql()) { // Show a more informative error message if using mysql with skip-innodb
                global $db;
                $result = $db->Execute("SHOW VARIABLES LIKE 'have_innodb'");
                if ($result->fields['Value'] != 'YES') {
                    throw new ConfigSanityException("Mahara requires InnoDB tables.  Please ensure InnoDB tables are enabled in your MySQL server.");
                }
            }
71
72
73
74
75
76
            $core = new StdClass;
            $core->install = true;
            $core->to = $config->version;
            $core->torelease = $config->release;
            $toupgrade['core'] = $core;
            $installing = true;
Elliot Pahl's avatar
Elliot Pahl committed
77
        }
78
        else if ($config->version > $coreversion) {
79
            $corerelease = get_config('release');
Elliot Pahl's avatar
Elliot Pahl committed
80
            if (isset($config->minupgradefrom) && isset($config->minupgraderelease)
81
                && $coreversion < $config->minupgradefrom) {
82
                throw new ConfigSanityException("Must upgrade to $config->minupgradefrom "
83
84
                                          . "($config->minupgraderelease) first "
                                          . " (you have $coreversion ($corerelease)");
85
            }
86
87
88
            $core = new StdClass;
            $core->upgrade = true;
            $core->from = $coreversion;
89
            $core->fromrelease = $corerelease;
90
91
92
93
94
95
            $core->to = $config->version;
            $core->torelease = $config->release;
            $toupgrade['core'] = $core;
        }
    }

96
    // If we were just checking if the core needed to be upgraded, we can stop here
97
    if ($name == 'core') {
98
        $toupgrade['core']->disablelogin = $disablelogin;
99
100
101
        return $toupgrade['core'];
    }

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    if (!$installing && (empty($name) || $name == 'local')) {
        $localversion = get_config('localversion');
        $localrelease = get_config('localrelease');
        if (is_null($localversion)) {
            $localversion = 0;
            $localrelease = 0;
        }

        $config = new StdClass;
        require(get_config('docroot') . 'local/version.php');

        if ($config->version > $localversion) {
            $toupgrade['local'] = (object) array(
                'upgrade'     => true,
                'from'        => $localversion,
                'fromrelease' => $localrelease,
                'to'          => $config->version,
                'torelease'   => $config->release,
            );
        }

        if ($name == 'local') {
            $toupgrade['local']->disablelogin = $disablelogin;
            return $toupgrade['local'];
        }
    }

129
130
    $plugins = array();
    if (!empty($name)) {
131
132
133
134
135
136
        try {
            $bits = explode('.', $name);
            $pt = $bits[0];
            $pn = $bits[1];
            $pp = null;
            if ($pt == 'blocktype' && strpos($pn, '/') !== false) {
137
                $bits = explode('/', $pn);
138
139
140
141
142
143
                $pp = get_config('docroot') . 'artefact/' . $bits[0]  . '/blocktype/' . $bits[1];
            }
            validate_plugin($pt, $pn, $pp);
            $plugins[] = explode('.', $name);
        }
        catch (InstallationException $_e) {
144
            log_warn("Plugin $pt $pn is not installable: " . $_e->GetMessage());
145
        }
146
147
148
149
150
151
152
153
154
155
156
    }
    else {
        foreach ($pluginstocheck as $plugin) {
            $dirhandle = opendir(get_config('docroot') . $plugin);
            while (false !== ($dir = readdir($dirhandle))) {
                if (strpos($dir, '.') === 0) {
                    continue;
                }
                if (!is_dir(get_config('docroot') . $plugin . '/' . $dir)) {
                    continue;
                }
157
158
159
160
161
                try {
                    validate_plugin($plugin, $dir);
                    $plugins[] = array($plugin, $dir);
                }
                catch (InstallationException $_e) {
162
                    log_warn("Plugin $plugin $dir is not installable: " . $_e->GetMessage());
163
164
165
                }

                if ($plugin == 'artefact') { // go check it for blocks as well
166
                    $btlocation = get_config('docroot') . $plugin . '/' . $dir . '/blocktype';
167
                    if (!is_dir($btlocation)) {
168
                        continue;
Elliot Pahl's avatar
Elliot Pahl committed
169
                    }
170
171
172
173
174
                    $btdirhandle = opendir($btlocation);
                    while (false !== ($btdir = readdir($btdirhandle))) {
                        if (strpos($btdir, '.') === 0) {
                            continue;
                        }
175
                        if (!is_dir(get_config('docroot') . $plugin . '/' . $dir . '/blocktype/' . $btdir)) {
176
177
178
                            continue;
                        }
                        $plugins[] = array('blocktype', $dir . '/' . $btdir);
179
180
                    }
                }
181
182
183
184
185
186
187
188
189
190
            }
        }
    }

    foreach ($plugins as $plugin) {
        $plugintype = $plugin[0];
        $pluginname = $plugin[1];
        $pluginpath = "$plugin[0]/$plugin[1]";
        $pluginkey  = "$plugin[0].$plugin[1]";

191
192
193
194
195
196
        if ($plugintype == 'blocktype' && strpos($pluginname, '/') !== false) {
            // sigh.. we're a bit special...
            $bits = explode('/', $pluginname);
            $pluginpath = 'artefact/' . $bits[0] . '/blocktype/' . $bits[1];
        }

197
198
199
        // Don't try to get the plugin info if we are installing - it will
        // definitely fail
        $pluginversion = 0;
200
201
202
203
204
205
206
207
208
        if (!$installing && table_exists(new XMLDBTable($plugintype . '_installed'))) {
            if ($plugintype == 'blocktype' && strpos($pluginname, '/')) {
                $bits = explode('/', $pluginname);
                $installed = get_record('blocktype_installed', 'name', $bits[1], 'artefactplugin', $bits[0]);
            }
            else {
                $installed = get_record($plugintype . '_installed', 'name', $pluginname);
            }
            if ($installed) {
209
210
211
                $pluginversion = $installed->version;
                $pluginrelease =  $installed->release;
            }
212
        }
213
214

        $config = new StdClass;
215
216
217
        require(get_config('docroot') . $pluginpath . '/version.php');
        if (isset($config->disablelogin) && !empty($config->disablelogin)) {
            $disablelogin = true;
218
219
220
        }

        if (empty($pluginversion)) {
221
222
223
            if (empty($installing) && $pluginkey != $name) {
                continue;
            }
224
225
226
227
            $plugininfo = new StdClass;
            $plugininfo->install = true;
            $plugininfo->to = $config->version;
            $plugininfo->torelease = $config->release;
228
229
230
231
232
233
            if (property_exists($config, 'requires_config')) {
                $plugininfo->requires_config = $config->requires_config;
            }
            if (property_exists($config, 'requires_parent')) {
                $plugininfo->requires_parent = $config->requires_parent;
            }
234
235
236
            $toupgrade[$pluginkey] = $plugininfo;
        }
        else if ($config->version > $pluginversion) {
237
238
239
240
241
            if (isset($config->minupgradefrom) && isset($config->minupgraderelease)
                && $pluginversion < $config->minupgradefrom) {
                throw new ConfigSanityException("Must upgrade to $config->minupgradefrom "
                                          . " ($config->minupgraderelease) first "
                                          . " (you have $pluginversion ($pluginrelease))");
242
            }
243
244
245
246
247
248
            $plugininfo = new StdClass;
            $plugininfo->upgrade = true;
            $plugininfo->from = $pluginversion;
            $plugininfo->fromrelease = $pluginrelease;
            $plugininfo->to = $config->version;
            $plugininfo->torelease = $config->release;
249
250
251
252
253
254
            if (property_exists($config, 'requires_config')) {
                $plugininfo->requires_config = $config->requires_config;
            }
            if (property_exists($config, 'requires_parent')) {
                $plugininfo->requires_parent = $config->requires_parent;
            }
255
256
257
258
259
260
261
262
263
264
265
            $toupgrade[$pluginkey] = $plugininfo;
        }
    }

    // if we've just asked for one, don't return an array...
    if (!empty($name) && count($toupgrade) == 1) {
        $upgrade = new StdClass;
        $upgrade->name = $name;
        foreach ((array)$toupgrade[$name] as $key => $value) {
            $upgrade->{$key} = $value;
        }
266
        $upgrade->disablelogin = $disablelogin;
267
268
        return $upgrade;
    }
269
    $toupgrade['disablelogin'] = $disablelogin;
270
271
272
    if (count($toupgrade) == 1) {
        $toupgrade = array();
    }
273
    uksort($toupgrade, 'sort_upgrades');
274
275
276
    return $toupgrade;
}

277
278
279
280
281
/**
 * Upgrades the core system to given upgrade version.
 *
 * @param object $upgrade   The version to upgrade to
 * @return bool             Whether the upgrade succeeded or not
282
 * @throws SQLException     If the upgrade failed due to a database error
283
 */
284
285
286
function upgrade_core($upgrade) {
    global $db;

287
    $location = get_config('libroot') . 'db/';
Penny Leach's avatar
Penny Leach committed
288
289

    db_begin();
290
291

    if (!empty($upgrade->install)) {
292
        install_from_xmldb_file($location . 'install.xml');
293
294
295
    }
    else {
        require_once($location . 'upgrade.php');
Penny Leach's avatar
Penny Leach committed
296
        xmldb_core_upgrade($upgrade->from);
297
298
    }

Penny Leach's avatar
Penny Leach committed
299
300
    set_config('version', $upgrade->to);
    set_config('release', $upgrade->torelease);
Elliot Pahl's avatar
Elliot Pahl committed
301

302
    if (!empty($upgrade->install)) {
Penny Leach's avatar
Penny Leach committed
303
        core_postinst();
304
    }
305

Penny Leach's avatar
Penny Leach committed
306
307
    db_commit();
    return true;
308
309
}

310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
/**
 * Upgrades local customisations.
 *
 * @param object $upgrade   The version to upgrade to
 * @return bool             Whether the upgrade succeeded or not
 * @throws SQLException     If the upgrade failed due to a database error
 */
function upgrade_local($upgrade) {
    db_begin();

    require_once(get_config('docroot') . 'local/upgrade.php');
    xmldb_local_upgrade($upgrade->from);

    set_config('localversion', $upgrade->to);
    set_config('localrelease', $upgrade->torelease);

    db_commit();
    return true;
}

330
331
332
333
334
/**
 * Upgrades the plugin to a new version
 *
 * @param object $upgrade   Information about the plugin to upgrade
 * @return bool             Whether the upgrade succeeded or not
335
 * @throws SQLException     If the upgrade failed due to a database error
336
 */
337
338
339
340
341
342
343
344
function upgrade_plugin($upgrade) {
    global $db;

    $plugintype = '';
    $pluginname = '';

    list($plugintype, $pluginname) = explode('.', $upgrade->name);

345
346
    if ($plugintype == 'blocktype' && strpos($pluginname, '/') !== false) {
        list($artefactplugin, $blocktypename) = explode('/', $pluginname);
Elliot Pahl's avatar
Elliot Pahl committed
347
    }
348

349
    $location = get_config('docroot') . $plugintype . '/' . $pluginname . '/db/';
350
    db_begin();
351
352
353

    if (!empty($upgrade->install)) {
        if (is_readable($location . 'install.xml')) {
354
            install_from_xmldb_file($location . 'install.xml');
355
356
357
358
359
360
        }
    }
    else {
        if (is_readable($location .  'upgrade.php')) {
            require_once($location . 'upgrade.php');
            $function = 'xmldb_' . $plugintype . '_' . $pluginname . '_upgrade';
361
362
363
            if (!$function($upgrade->from)) {
                throw new InstallationException("Failed to run " . $function . " (check logs for errors)");
            }
364
365
366
367
368
369
370
        }
    }

    $installed = new StdClass;
    $installed->name = $pluginname;
    $installed->version = $upgrade->to;
    $installed->release = $upgrade->torelease;
371
372
373
374
375
376
377
378
    if ($plugintype == 'blocktype') {
        if (!empty($blocktypename)) {
            $installed->name = $blocktypename;
        }
        if (!empty($artefactplugin)) { // blocks come from artefactplugins.
            $installed->artefactplugin = $artefactplugin;
        }
    }
379
380
381
382
383
384
    if (property_exists($upgrade, 'requires_config')) {
        $installed->requires_config = $upgrade->requires_config;
    }
    if (property_exists($upgrade, 'requires_parent')) {
        $installed->requires_parent = $upgrade->requires_parent;
    }
385
    $installtable = $plugintype . '_installed';
386
387
388

    if (!empty($upgrade->install)) {
        insert_record($installtable,$installed);
Elliot Pahl's avatar
Elliot Pahl committed
389
    }
390
391
392
393
394
    else {
        update_record($installtable, $installed, 'name');
    }

    // postinst stuff...
Nigel McNie's avatar
Nigel McNie committed
395
    safe_require($plugintype, $pluginname);
396
    $pcname = generate_class_name($plugintype, $installed->name);
397
398
399
400
401
402
403
404
405
406
407

    if ($crons = call_static_method($pcname, 'get_cron')) {
        foreach ($crons as $cron) {
            $cron = (object)$cron;
            if (empty($cron->callfunction)) {
                throw new InstallationException("cron for $pcname didn't supply function name");
            }
            if (!is_callable(array($pcname, $cron->callfunction))) {
                throw new InstallationException("cron $cron->callfunction for $pcname supplied but wasn't callable");
            }
            $new = false;
408
            $table = $plugintype . '_cron';
409
410
411
            if (!empty($upgrade->install)) {
                $new = true;
            }
412
            else if (!record_exists($table, 'plugin', $pluginname, 'callfunction', $cron->callfunction)) {
413
414
415
416
                $new = true;
            }
            $cron->plugin = $pluginname;
            if (!empty($new)) {
417
                insert_record($table, $cron);
418
419
            }
            else {
420
                update_record($table, $cron, array('plugin', 'callfunction'));
421
422
423
            }
        }
    }
Elliot Pahl's avatar
Elliot Pahl committed
424

425
426
427
428
    if ($events = call_static_method($pcname, 'get_event_subscriptions')) {
        foreach ($events as $event) {
            $event = (object)$event;

429
            if (!record_exists('event_type', 'name', $event->event)) {
430
431
432
433
434
435
436
437
438
                throw new InstallationException("event $event->event for $pcname doesn't exist!");
            }
            if (empty($event->callfunction)) {
                throw new InstallationException("event $event->event for $pcname didn't supply function name");
            }
            if (!is_callable(array($pcname, $event->callfunction))) {
                throw new InstallationException("event $event->event with function $event->callfunction for $pcname supplied but wasn't callable");
            }
            $exists = false;
439
            $table = $plugintype . '_event_subscription';
440
            $block = blocktype_namespaced_to_single($pluginname);
441
            if (empty($upgrade->install)) {
442
                $exists = get_record($table, 'plugin' , $block, 'event', $event->event);
443
            }
444
            $event->plugin = $block;
445
            if (empty($exists)) {
446
                insert_record($table, $event);
447
448
            }
            else {
449
                update_record($table, $event, array('id' => $exists->id));
450
451
452
453
            }
        }
    }

454
455
456
457
458
459
460
461
462
463
464
    if ($activities = call_static_method($pcname, 'get_activity_types')) {
        foreach ($activities as $activity) {
            $classname = 'ActivityType' . ucfirst($plugintype) . ucfirst($pluginname) . ucfirst($activity->name);
            if (!class_exists($classname)) {
                throw new InstallationException(get_string('classmissing', 'error',  $classname, $pluginname, $plugintype));
            }
            $activity->plugintype = $plugintype;
            $activity->pluginname = $pluginname;
            $where = $activity;
            unset($where->admin);
            unset($where->delay);
465
            // Work around the fact that insert_record cached the columns that
466
467
468
            // _were_ in the activity_type table before it was upgraded
            global $INSERTRECORD_NOCACHE;
            $INSERTRECORD_NOCACHE = true;
469
            ensure_record_exists('activity_type', $where, $activity);
470
            unset($INSERTRECORD_NOCACHE);
471
472
473
        }
    }

474
475
     // install artefact types
    if ($plugintype == 'artefact') {
476
477
478
        if (!is_callable(array($pcname, 'get_artefact_types'))) {
            throw new InstallationException("Artefact plugin $pcname must implement get_artefact_types and doesn't");
        }
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
        $types = call_static_method($pcname, 'get_artefact_types');
        $ph = array();
        if (is_array($types)) {
            foreach ($types as $type) {
                $ph[] = '?';
                if (!record_exists('artefact_installed_type', 'plugin', $pluginname, 'name', $type)) {
                    $t = new StdClass;
                    $t->name = $type;
                    $t->plugin = $pluginname;
                    insert_record('artefact_installed_type',$t);
                }
            }
            $select = '(plugin = ? AND name NOT IN (' . implode(',', $ph) . '))';
            delete_records_select('artefact_installed_type', $select,
                                  array_merge(array($pluginname),$types));
        }
    }
Elliot Pahl's avatar
Elliot Pahl committed
496

497
498
499
    // install blocktype categories.
    if ($plugintype == 'blocktype' && get_config('installed')) {
        install_blocktype_categories_for_plugin($pluginname);
500
        install_blocktype_viewtypes_for_plugin($pluginname);
501
502
    }

503
504
    $prevversion = (empty($upgrade->install)) ? $upgrade->from : 0;
    call_static_method($pcname, 'postinst', $prevversion);
Elliot Pahl's avatar
Elliot Pahl committed
505

506
507
    db_commit();
    return true;
508
509
510
511
512
513
514
}

function core_postinst() {
    $status = true;
    $pages = site_content_pages();
    $now = db_format_timestamp(time());
    foreach ($pages as $name) {
Donal McMullan's avatar
Donal McMullan committed
515
        $page = new stdClass();
516
517
518
519
520
521
522
523
        $page->name = $name;
        $page->ctime = $now;
        $page->mtime = $now;
        $page->content = get_string($page->name . 'defaultcontent', 'install');
        if (!insert_record('site_content',$page)) {
            $status = false;
        }
    }
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555

    // Attempt to create session directories
    $sessionpath = get_config('dataroot') . 'sessions';
    if (check_dir_exists($sessionpath)) {
        // Create three levels of directories, named 0-9, a-f
        $characters = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
        foreach ($characters as $c1) {
            if (check_dir_exists("$sessionpath/$c1")) {
                foreach ($characters as $c2) {
                    if (check_dir_exists("$sessionpath/$c1/$c2")) {
                        foreach ($characters as $c3) {
                            if (!check_dir_exists("$sessionpath/$c1/$c2/$c3")) {
                                $status = false;
                                break(3);
                            }
                        }
                    }
                    else {
                        $status = false;
                        break(2);
                    }
                }
            }
            else {
                $status = false;
                break;
            }
        }
    }
    else {
        $status = false;
    }
556
557
558
559

    // Set default search plugin
    set_config('searchplugin', 'internal');

560
    set_config('lang', 'en.utf8');
561
    set_config('installation_key', get_random_key());
562

563
564
    // PostgreSQL supports indexes over functions of columns, MySQL does not. 
    // We make use if this if we can
565
    if (is_postgres()) {
566
        // Improve the username index
567
568
        execute_sql('DROP INDEX {usr_use_uix}');
        execute_sql('CREATE UNIQUE INDEX {usr_use_uix} ON {usr}(LOWER(username))');
569
570
571

        // Only one profile view per user
        execute_sql("CREATE UNIQUE INDEX {view_own_type_uix} ON {view}(owner) WHERE type = 'profile'");
572
573
    }

574
575
576
577
578
579
580
581
582
583
584
585
    // Some more advanced constraints. XMLDB can't handle this in its xml file format
    execute_sql('ALTER TABLE {artefact} ADD CHECK (
        (owner IS NOT NULL AND "group" IS NULL     AND institution IS NULL) OR
        (owner IS NULL     AND "group" IS NOT NULL AND institution IS NULL) OR
        (owner IS NULL     AND "group" IS NULL     AND institution IS NOT NULL)
    )');
    execute_sql('ALTER TABLE {view} ADD CHECK (
        (owner IS NOT NULL AND "group" IS NULL     AND institution IS NULL) OR
        (owner IS NULL     AND "group" IS NOT NULL AND institution IS NULL) OR
        (owner IS NULL     AND "group" IS NULL     AND institution IS NOT NULL)
    )');

586
    reload_html_filters();
587
    return $status;
588
589
}

590
function core_install_lastcoredata_defaults() {
591
    global $USER;
592
    db_begin();
593
    $institution = new StdClass;
594
595
596
    $institution->name = 'mahara';
    $institution->displayname = 'No Institution';
    $institution->authplugin  = 'internal';
597
    $institution->theme  = 'default';
598
    insert_record('institution', $institution);
599

600
    $auth_instance = new StdClass;
601
    $auth_instance->instancename  = 'Internal';
602
    $auth_instance->priority='1';
603
604
    $auth_instance->institution   = 'mahara';
    $auth_instance->authname      = 'internal';
605
606
    $auth_instance->id = insert_record('auth_instance', $auth_instance, 'id', true);

607
608
609
610
611
612
613
614
615
    // Insert the root user
    $user = new StdClass;
    $user->id = 0;
    $user->username = 'root';
    $user->password = '*';
    $user->salt = '*';
    $user->firstname = 'System';
    $user->lastname = 'User';
    $user->email = 'root@example.org';
616
    $user->quota = get_config_plugin('artefact', 'file', 'defaultquota');
617
    $user->authinstance = $auth_instance->id;
618

619
620
    if (is_mysql()) { // gratuitous mysql workaround
        $newid = insert_record('usr', $user, 'id', true);
621
        set_field('usr', 'id', 0, 'id', $newid);
622
        execute_sql('ALTER TABLE {usr} AUTO_INCREMENT=1');
623
    }
624
625
626
    else {
        insert_record('usr', $user);
    }
627

628
629
    install_system_profile_view();

630
    // Insert the admin user
631
632
633
    $user = new StdClass;
    $user->username = 'admin';
    $user->password = 'mahara';
634
    $user->authinstance = $auth_instance->id;
635
636
637
638
639
    $user->passwordchange = 1;
    $user->admin = 1;
    $user->firstname = 'Admin';
    $user->lastname = 'User';
    $user->email = 'admin@example.org';
640
    $user->quota = get_config_plugin('artefact', 'file', 'defaultquota');
641
642
643
644
    $user->id = insert_record('usr', $user, 'id', true);
    set_profile_field($user->id, 'email', $user->email);
    set_profile_field($user->id, 'firstname', $user->firstname);
    set_profile_field($user->id, 'lastname', $user->lastname);
645
    handle_event('createuser', $user->id);
646
    activity_add_admin_defaults(array($user->id));
647
    db_commit();
648
649

    // if we're installing, set up the block categories here and then poll the plugins.
Elliot Pahl's avatar
Elliot Pahl committed
650
    // if we're upgrading this happens somewhere else.  This is because of dependency issues around
651
652
    // the order of installation stuff.

653
    install_blocktype_extras();
654
655
}

656
657
658
function core_install_firstcoredata_defaults() {
    // Install the default institution
    db_begin();
Elliot Pahl's avatar
Elliot Pahl committed
659

660
    set_config('session_timeout', 86400);
661
    set_config('sitename', 'Mahara');
662
    set_config('defaultaccountinactivewarn', 604800);
663
    set_config('createpublicgroups', 'all');
664
    set_config('allowpublicviews', 1);
665
    set_config('allowpublicprofiles', 1);
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692

    // install the applications
    $app = new StdClass;
    $app->name = 'mahara';
    $app->displayname = 'Mahara';
    $app->xmlrpcserverurl = '/api/xmlrpc/server.php';
    $app->ssolandurl = '/auth/xmlrpc/land.php';
    insert_record('application', $app);

    $app->name = 'moodle';
    $app->displayname = 'Moodle';
    $app->xmlrpcserverurl = '/mnet/xmlrpc/server.php';
    $app->ssolandurl = '/auth/mnet/land.php';
    insert_record('application', $app);

    // insert the event types
    $eventtypes = array(
        'createuser',
        'updateuser',
        'suspenduser',
        'unsuspenduser',
        'deleteuser',
        'undeleteuser',
        'expireuser',
        'unexpireuser',
        'deactivateuser',
        'activateuser',
693
        'userjoinsgroup',
694
695
696
697
        'saveartefact',
        'deleteartefact',
        'saveview',
        'deleteview',
698
        'blockinstancecommit',
699
700
701
702
        'addfriend',
        'removefriend',
        'addfriendrequest',
        'removefriendrequest',
703
704
705
706
707
708
709
710
    );

    foreach ($eventtypes as $et) {
        $e = new StdClass;
        $e->name = $et;
        insert_record('event_type', $e);
    }

711
712
713
714
715
    // install the core event subscriptions
    $subs = array(
        array(
            'event'        => 'createuser',
            'callfunction' => 'activity_set_defaults',
716
        ),
717
718
719
720
        array(
            'event'        => 'createuser',
            'callfunction' => 'add_user_to_autoadd_groups',
        ),
721
722
723
724
725
    );

    foreach ($subs as $sub) {
        insert_record('event_subscription', (object)$sub);
    }
Elliot Pahl's avatar
Elliot Pahl committed
726

727
728
729
730
731
732
733
734
735
736
737
    // install the activity types
    $activitytypes = array(
        array('maharamessage', 0, 0),
        array('usermessage', 0, 0),
        array('feedback', 0, 0),
        array('watchlist', 0, 1),
        array('viewaccess', 0, 1),
        array('contactus', 1, 1),
        array('objectionable', 1, 1),
        array('virusrepeat', 1, 1),
        array('virusrelease', 1, 1),
738
        array('institutionmessage', 0, 0),
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
    );

    foreach ($activitytypes as $at) {
        $a = new StdClass;
        $a->name = $at[0];
        $a->admin = $at[1];
        $a->delay = $at[2];
        insert_record('activity_type', $a);
    }

    // install the cronjobs...
    $cronjobs = array(
        'rebuild_artefact_parent_cache_dirty'    => array('*', '*', '*', '*', '*'),
        'rebuild_artefact_parent_cache_complete' => array('0', '4', '*', '*', '*'),
        'auth_clean_partial_registrations'       => array('5', '0', '*', '*', '*'),
        'auth_handle_account_expiries'           => array('5', '10', '*', '*', '*'),
755
        'auth_handle_institution_expiries'       => array('5', '9', '*', '*', '*'),
756
        'activity_process_queue'                 => array('*/5', '*', '*', '*', '*'),
757
        'auth_remove_old_session_files'          => array('30', '20', '*', '*', '*'),
758
        'recalculate_quota'                      => array('15', '2', '*', '*', '*'),
759
        'import_process_queue'                   => array('*/5', '*', '*', '*', '*'),
760
        'cron_send_registration_data'            => array(rand(0, 59), rand(0, 23), '*', '*', rand(0, 6)),
761
        'export_cleanup_old_exports'             => array('0', '3,13', '*', '*', '*'),
762
763
764
765
766
767
768
769
770
771
772
    );
    foreach ($cronjobs as $callfunction => $times) {
        $cron = new StdClass;
        $cron->callfunction = $callfunction;
        $cron->minute       = $times[0];
        $cron->hour         = $times[1];
        $cron->day          = $times[2];
        $cron->month        = $times[3];
        $cron->dayofweek    = $times[4];
        insert_record('cron', $cron);
    }
Elliot Pahl's avatar
Elliot Pahl committed
773

774
    // install the view column widths
775
    install_view_column_widths();
776

777
778
779
780
781
782
    $viewtypes = array('portfolio', 'profile');
    foreach ($viewtypes as $vt) {
        insert_record('view_type', (object)array(
            'type' => $vt,
        ));
    }
783
784
785
786
    db_commit();
}


Elliot Pahl's avatar
Elliot Pahl committed
787
788
789
/**
 * xmldb will pass us the xml file and we can perform any substitution as necessary
 */
790
function local_xmldb_contents_sub(&$contents) {
791
    // the main install.xml file needs to sub in plugintype tables.
792
793
794
795
796
797
798
799
800
    $searchstring = '<!-- PLUGIN_TYPE_SUBSTITUTION -->';
    if (strstr($contents, $searchstring) === 0) {
        return;
    }
    // ok, we're in the main file and we need to install all the plugin tables
    // get the basic skeleton structure
    $plugintables = file_get_contents(get_config('docroot') . 'lib/db/plugintables.xml');
    $tosub = '';
    foreach (plugin_types() as $plugin) {
Elliot Pahl's avatar
Elliot Pahl committed
801
        // any that want their own stuff can put it in docroot/plugintype/lib/db/plugintables.xml
802
        //- like auth is a bit special
803
804
805
        $specialcase = get_config('docroot') . $plugin . '/plugintables.xml';
        if (is_readable($specialcase)) {
            $tosub .= file_get_contents($specialcase) . "\n";
Elliot Pahl's avatar
Elliot Pahl committed
806
        }
807
        else {
808
809
810
811
812
813
814
815
            $replaced = '';
            // look for tables to put at the start...
            $pretables = get_config('docroot') . $plugin . '/beforetables.xml';
            if (is_readable($pretables)) {
                $replaced = file_get_contents($pretables) . "\n";
            }

            // perform any additional once off substitutions
816
817
            require_once(get_config('docroot') . $plugin . '/lib.php');
            if (method_exists(generate_class_name($plugin), 'extra_xmldb_substitution')) {
818
                $replaced  .= call_static_method(generate_class_name($plugin), 'extra_xmldb_substitution', $plugintables);
819
            }
820
            else {
821
                $replaced .= $plugintables;
822
            }
823
            $tosub .= str_replace('__PLUGINTYPE__', $plugin, $replaced) . "\n";
824
            // look for any tables to put at the end..
825
826
827
            $extratables = get_config('docroot') . $plugin . '/extratables.xml';
            if (is_readable($extratables)) {
                $tosub .= file_get_contents($extratables) . "\n";
828
            }
829
830
        }
    }
831
    $contents = str_replace($searchstring, $tosub, $contents);
832
833
}

834
835
836
837
838
839
840
841

/**
 * validates a plugin for installation
 * @throws InstallationException
*/
function validate_plugin($plugintype, $pluginname, $pluginpath='') {

    if (empty($pluginpath)) {
842
        $pluginpath = get_config('docroot') . $plugintype . '/' . $pluginname;
843
844
845
846
    }
    if (!file_exists($pluginpath . '/version.php')) {
        throw new InstallationException(get_string('versionphpmissing', 'error', $plugintype, $pluginname));
    }
847
848
849
850
851
852
    safe_require($plugintype, $pluginname);
    $classname = generate_class_name($plugintype, $pluginname);
    if (!class_exists($classname)) {
        throw new InstallationException(get_string('classmissing', 'error', $classname, $plugintype, $pluginname));
    }
    require_once(get_config('docroot') . $plugintype . '/lib.php');
853
854
855
856
857
    $funname = $plugintype . '_check_plugin_sanity';
    if (function_exists($funname)) {
        $funname($pluginname);
    }
}
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875

/*
* the order things are installed/upgraded in matters
*/

function sort_upgrades($k1, $k2) {
    if ($k1 == 'core') {
        return -1;
    }
    else if ($k2 == 'core') {
        return 1;
    }
    else if ($k1 == 'firstcoredata') {
        return -1;
    }
    else if ($k2 == 'firstcoredata') {
        return 1;
    }
876
877
878
879
880
881
882
883
884
885
886
887
    else if ($k1 == 'localpreinst') {
        return -1;
    }
    else if ($k2 == 'localpreinst') {
        return 1;
    }
    else if ($k1 == 'localpostinst') {
        return 1;
    }
    else if ($k2 == 'localpostinst') {
        return -1;
    }
888
889
890
891
892
893
    else if ($k1 == 'lastcoredata') {
        return 1;
    }
    else if ($k2 == 'lastcoredata') {
        return -1;
    }
894
895
896
897
    // else obey the order plugin types returns (strip off plugintype. from the start)
    $weight1 = array_search(substr($k1, 0, strpos($k1, '.')), plugin_types());
    $weight2 = array_search(substr($k2, 0, strpos($k2, '.')), plugin_types());
    return ($weight1 > $weight2);
898
}
899

900
/** blocktype categories the system exports (including artefact categories)
901
*/
902
903
function get_blocktype_categories() {
    return array('general', 'internal', 'blog', 'resume', 'fileimagevideo', 'feeds');
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
}

function install_blocktype_categories_for_plugin($blocktype) {
    safe_require('blocktype', $blocktype);
    $blocktype = blocktype_namespaced_to_single($blocktype);
    db_begin();
    delete_records('blocktype_installed_category', 'blocktype', $blocktype);
    if ($cats = call_static_method(generate_class_name('blocktype', $blocktype), 'get_categories')) {
        foreach ($cats as $cat) {
            insert_record('blocktype_installed_category', (object)array(
                'blocktype' => $blocktype,
                'category' => $cat
            ));
        }
    }
    db_commit();
}

922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
function install_blocktype_viewtypes_for_plugin($blocktype) {
    safe_require('blocktype', $blocktype);
    $blocktype = blocktype_namespaced_to_single($blocktype);
    db_begin();
    delete_records('blocktype_installed_viewtype', 'blocktype', $blocktype);
    if ($viewtypes = call_static_method(generate_class_name('blocktype', $blocktype), 'get_viewtypes')) {
        foreach($viewtypes as $vt) {
            insert_record('blocktype_installed_viewtype', (object)array(
                'blocktype' => $blocktype,
                'viewtype'  => $vt,
            ));
        }
    }
    db_commit();
}

function install_blocktype_extras() {
939
940
    db_begin();

941
    $categories = get_blocktype_categories();
942
943
944
945
946
947
948
949
950
951
952
953
    $installedcategories = get_column('blocktype_category', 'name');

    if ($toinstall = array_diff($categories, $installedcategories)) {
        foreach ($toinstall as $i) {
            insert_record('blocktype_category', (object)array('name' => $i));
        }
    }

    db_commit();


    // poll all the installed blocktype plugins and ask them what categories they export
954
    if ($blocktypes = plugins_installed('blocktype', true)) {
955
956
        foreach ($blocktypes as $bt) {
            install_blocktype_categories_for_plugin(blocktype_single_to_namespaced($bt->name, $bt->artefactplugin));
957
            install_blocktype_viewtypes_for_plugin(blocktype_single_to_namespaced($bt->name, $bt->artefactplugin));
958
959
960
961
        }
    }
}

962
/**
Elliot Pahl's avatar
Elliot Pahl committed
963
 * Installs all the allowed column widths for views. Used when installing core
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
 * defaults, and also when upgrading from 0.8 to 0.9
 */
function install_view_column_widths() {
    db_begin();
    $layouts = array(
        2 => array(
            '50,50',
            '67,33',
            '33,67',
            ),
        3 => array(
            '33,33,33',
            '25,50,25',
            '15,70,15',
            ),
        4 => array(
            '25,25,25,25',
            '20,30,30,20',
            ),
    );

    $layout = new StdClass;
    foreach ($layouts as $column => $widths) {
        foreach ($widths as $width) {
            $layout->columns = $column;
            $layout->widths = $width;
            insert_record('view_layout', $layout);
        }
    }
    db_commit();
}

996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
/**
 * Reload htmlpurifier filters from the XML configuration file.
 */
function reload_html_filters() {
    require_once('xmlize.php');
    log_info('Reading HTML filters');

    $newlist = xmlize(file_get_contents(get_config('libroot') . 'htmlpurifiercustom/filters.xml'));
    $filters = $newlist['filters']['#']['filter'];
    foreach ($filters as &$f) {
        $f = (object) array(
            'site' => $f['#']['site'][0]['#'],
            'file' => $f['#']['filename'][0]['#']
        );
        log_info('- ' . $f->file);
    }
    $filters[] = (object) array('site' => 'http://www.youtube.com', 'file' => 'YouTube');
    log_info('- YouTube');
    set_config('filters', serialize($filters));
}
1016
?>