upgrade.php 15.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
/**
 * This program is part of Mahara
 *
 *  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 2 of the License, or
 *  (at your option) any later version.
 *
 *  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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 *
 * @package    mahara
20
21
 * @subpackage core
 * @author     Penny Leach <penny@catalyst.net.nz>
22
23
24
25
26
27
28
29
30
31
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
 * @copyright  (C) 2006,2007 Catalyst IT Ltd http://catalyst.net.nz
 *
 */

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

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


/**
36
37
38
39
40
 * 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
41
 */
42
function check_upgrades($name=null) {
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
 
    $pluginstocheck = plugin_types();

    $toupgrade = array();
    $installing = false;

    require('version.php');
    // check core first...
    if (empty($name) || $name == 'core') {
        try {
            $coreversion = get_config('version');
        } 
        catch (Exception $e) {
            $coreversion = 0;
        }
        if (empty($coreversion)) {
            $core = new StdClass;
            $core->install = true;
            $core->to = $config->version;
            $core->torelease = $config->release;
            $toupgrade['core'] = $core;
            $installing = true;
        } 
        else if ($config->version > $coreversion) {
            $core = new StdClass;
            $core->upgrade = true;
            $core->from = $coreversion;
            $core->fromrelease = get_config('release');
            $core->to = $config->version;
            $core->torelease = $config->release;
            $toupgrade['core'] = $core;
        }
    }

77
    // If we were just checking if the core needed to be upgraded, we can stop here
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    if ($name == 'core') {
        return $toupgrade['core'];
    }

    $plugins = array();
    if (!empty($name)) {
        $plugins[] = explode('.', $name);
    }
    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;
                }
96
                require_once('artefact.php');
97
98
99
100
101
                $funname = $plugin . '_check_plugin_sanity';
                if (function_exists($funname)) {
                    try {
                        $funname($dir);
                    }
102
                    catch (InstallationException $e) {
103
104
105
106
                        log_warn("Plugin $plugin $dir is not installable: " . $e->GetMessage());
                        continue;
                    }
                }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
                $plugins[] = array($plugin, $dir);
            }
        }
    }

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

        
        // Don't try to get the plugin info if we are installing - it will
        // definitely fail
        $pluginversion = 0;
        if (!$installing) {
123
            if ($installed = get_record($plugintype . '_installed', 'name', $pluginname)) {
124
125
126
127
128
129
130
131
                $pluginversion = $installed->version;
                $pluginrelease =  $installed->release;
            }
            
            require(get_config('docroot') . $pluginpath . '/version.php');
        }

        if (empty($pluginversion)) {
132
133
134
            if (empty($installing) && $pluginkey != $name) {
                continue;
            }
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
            $plugininfo = new StdClass;
            $plugininfo->install = true;
            $plugininfo->to = $config->version;
            $plugininfo->torelease = $config->release;
            $toupgrade[$pluginkey] = $plugininfo;
        }
        else if ($config->version > $pluginversion) {
            $plugininfo = new StdClass;
            $plugininfo->upgrade = true;
            $plugininfo->from = $pluginversion;
            $plugininfo->fromrelease = $pluginrelease;
            $plugininfo->to = $config->version;
            $plugininfo->torelease = $config->release;
            $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;
        }
        return $upgrade;
    }
    return $toupgrade;
}

164
165
166
167
168
/**
 * Upgrades the core system to given upgrade version.
 *
 * @param object $upgrade   The version to upgrade to
 * @return bool             Whether the upgrade succeeded or not
169
 * @throws SQLException     If the upgrade failed due to a database error
170
 */
171
172
173
174
175
176
177
178
179
180
181
182
183
184
function upgrade_core($upgrade) {
    global $db;

    $location = get_config('libroot') . '/db/';
    $db->StartTrans();

    if (!empty($upgrade->install)) {
        $status = install_from_xmldb_file($location . 'install.xml'); 
    }
    else {
        require_once($location . 'upgrade.php');
        $status = xmldb_core_upgrade($upgrade->from);
    }
    if (!$status) {
185
        throw new SQLException("Failed to upgrade core");
186
187
188
189
190
191
192
193
    }

    $status = set_config('version', $upgrade->to);
    $status = $status && set_config('release', $upgrade->torelease);
    
    if ($db->HasFailedTrans()) {
        $status = false;
    }
194
195
196
197
    
    if (!empty($upgrade->install)) {
        $status = $status && core_postinst();
    }
198
199
200
201
202
203
204
    else {
        // only do this here if we're not installing
        // otherwise the default system user won't exist yet
        // and we have to do it in core_install_defaults
        require('template.php');
        upgrade_templates();
    }
205
    
206
207
208
209
210
    $db->CompleteTrans();

    return $status;
}

211
212
213
214
215
/**
 * Upgrades the plugin to a new version
 *
 * @param object $upgrade   Information about the plugin to upgrade
 * @return bool             Whether the upgrade succeeded or not
216
 * @throws SQLException     If the upgrade failed due to a database error
217
 */
218
219
220
221
222
223
224
225
function upgrade_plugin($upgrade) {
    global $db;

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

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

226
    $location = get_config('docroot') . $plugintype . '/' . $pluginname . '/db/';
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
    $db->StartTrans();

    if (!empty($upgrade->install)) {
        if (is_readable($location . 'install.xml')) {
            $status = install_from_xmldb_file($location . 'install.xml');
        }
        else {
            $status = true;
        }
    }
    else {
        if (is_readable($location .  'upgrade.php')) {
            require_once($location . 'upgrade.php');
            $function = 'xmldb_' . $plugintype . '_' . $pluginname . '_upgrade';
            $status = $function($upgrade->from);
        }
        else {
            $status = true;
        }
    }
    if (!$status || $db->HasFailedTrans()) {
        $db->CompleteTrans();
249
        throw new SQLException("Failed to upgrade $upgrade->name");
250
251
252
253
254
255
    }

    $installed = new StdClass;
    $installed->name = $pluginname;
    $installed->version = $upgrade->to;
    $installed->release = $upgrade->torelease;
256
    $installtable = $plugintype . '_installed';
257
258
259
260
261
262
263
264
265
266

    if (!empty($upgrade->install)) {
        insert_record($installtable,$installed);
    } 
    else {
        update_record($installtable, $installed, 'name');
    }

    // postinst stuff...
    safe_require($plugintype, $pluginname, 'lib.php');
267
    $pcname = generate_class_name($plugintype, $pluginname);
268
269
270
271
272
273
274
275
276
277
278
279
280

    if ($crons = call_static_method($pcname, 'get_cron')) {
        foreach ($crons as $cron) {
            $cron = (object)$cron;
            if (empty($cron->callfunction)) {
                $db->RollbackTrans();
                throw new InstallationException("cron for $pcname didn't supply function name");
            }
            if (!is_callable(array($pcname, $cron->callfunction))) {
                $db->RollbackTrans();
                throw new InstallationException("cron $cron->callfunction for $pcname supplied but wasn't callable");
            }
            $new = false;
281
            $table = $plugintype . '_cron';
282
283
284
            if (!empty($upgrade->install)) {
                $new = true;
            }
285
            else if (!record_exists($table, 'plugin', $pluginname, 'callfunction', $cron->callfunction)) {
286
287
288
289
                $new = true;
            }
            $cron->plugin = $pluginname;
            if (!empty($new)) {
290
                insert_record($table, $cron);
291
292
            }
            else {
293
                update_record($table, $cron, array('plugin', 'name'));
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
            }
        }
    }
    
    if ($events = call_static_method($pcname, 'get_event_subscriptions')) {
        foreach ($events as $event) {
            $event = (object)$event;

            if (!record_exists('event', 'name', $event->event)) {
                $db->RollbackTrans();
                throw new InstallationException("event $event->event for $pcname doesn't exist!");
            }
            if (empty($event->callfunction)) {
                $db->RollbackTrans();
                throw new InstallationException("event $event->event for $pcname didn't supply function name");
            }
            if (!is_callable(array($pcname, $event->callfunction))) {
                $db->RollbackTrans();
                throw new InstallationException("event $event->event with function $event->callfunction for $pcname supplied but wasn't callable");
            }
            $exists = false;
315
            $table = $plugtype . '_event_subscription';
316
            if (empty($upgrade->install)) {
317
                $exists = record_exists($table, 'plugin' , $pluginname, 'event', $event->event());
318
319
320
            }
            $event->plugin = $pluginname;
            if (empty($exists)) {
321
                insert_record($table, $event);
322
323
            }
            else {
324
                update_record($table, $event, array('id', $exists->id));
325
326
327
328
            }
        }
    }

329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
     // install artefact types
    if ($plugintype == 'artefact') {
        $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));
        }
    }

349
350
351
352
353
354
355
356
    call_static_method($pcname, 'postinst');
    
    if ($db->HasFailedTrans()) {
        $status = false;
    }
    $db->CompleteTrans();
    
    return $status;
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373

}

function core_postinst() {
    $status = true;
    $pages = site_content_pages();
    $now = db_format_timestamp(time());
    foreach ($pages as $name) {
        $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;
        }
    }
    return $status;
374
375
}

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413

function core_install_defaults() {
    // Install the default institution
    db_begin();
    $institution = new StdClass;
    $institution->name = 'mahara';
    $institution->displayname = 'No Institution';
    $institution->authplugin  = 'internal';
    insert_record('institution', $institution);
    
    // Insert the root user
    $user = new StdClass;
    $user->id = 0;
    $user->username = 'root';
    $user->password = '*';
    $user->salt = '*';
    $user->institution = 'mahara';
    $user->firstname = 'System';
    $user->lastname = 'User';
    $user->email = 'root@example.org';
    insert_record('usr', $user);

    // Insert the admin user
    $user = new StdClass;
    $user->username = 'admin';
    $user->password = 'mahara';
    $user->institution = 'mahara';
    $user->passwordchange = 1;
    $user->admin = 1;
    $user->firstname = 'Admin';
    $user->lastname = 'User';
    $user->email = 'admin@example.org';
    $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);
    
    require('template.php');
414
415
416
417
418
419
420
421
    try {
        upgrade_templates();
    }
    catch (TemplateParserException $e) {
        set_config('installed', true);
        db_commit();
        throw $e;
    }
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
    set_config('installed', true);
    db_commit();
}

function upgrade_templates() {

    $dbtemplates = array();

    // check dataroot first, they get precedence.
    $templates = get_dir_contents(get_config('dataroot') . 'templates/');
    foreach ($templates as $dir) {
        $dbtemplates[$dir] = template_parse($dir);
    }

    // and now system templates
    $templates = get_dir_contents(get_config('libroot') . 'templates/');
    foreach ($templates as $dir) {
        if (array_key_exists($dir, $dbtemplates)) { // dataroot gets preference
            continue;
        }
        $dbtemplates[$dir] = template_parse($dir);
    }

    foreach ($dbtemplates as $name => $guff) {
        if (!is_readable($guff['location'] . 'config.php')) {
447
            throw new TemplateParserException("missing config.php for template $name");
448
449
450
451
452
453
454
455
456
457
        }
        require_once($guff['location'] . 'config.php');
        $fordb = new StdClass;
        $fordb->name = $name;
        $fordb->mtime = db_format_timestamp(time());
        $fordb->title = $template->title;
        $fordb->description = $template->description;
        $fordb->category = $template->category;
        $fordb->mtime = db_format_timestamp(time());
        $fordb->cacheddata = serialize($guff['parseddata']);
Penny Leach's avatar
Penny Leach committed
458
459
460
        if (isset($guff['thumbnail'])) {
            $fordb->thumbnail = 1;
        }
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
        if (isset($template->owner)) {
            $fordb->owner = $template->owner;
        }
        else {
            $fordb->owner = 0; // root user
        }
        if (record_exists('template', 'name', $name)) {
            update_record('template', $fordb, 'name');
        }
        else {
            $fordb->ctime = $fordb->mtime;
            insert_record('template', $fordb);
        }
    }
    
    if (count($dbtemplates) > 0) {
        set_field_select('template', 'deleted', 1, 
                         'name NOT IN (' . implode(',', db_array_to_ph(array_keys($dbtemplates))). ')', 
                         array_keys($dbtemplates));
    }
    else {
        set_field('template', 'deleted', 1);
    }
    
}


488
?>