web.php 93.7 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
20
 *
 * @package    mahara
 * @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
 * @copyright  (C) portions from Moodle, (C) Martin Dougiamas http://dougiamas.com
 */

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


30
function &smarty_core() {
31
    global $THEME;
32
    require_once('smarty/libs/Smarty.class.php');
33
34
35
36
    $smarty =& new Smarty();
    
    $themepaths = themepaths();

37
    $smarty->template_dir = $THEME->templatedirs;
38

39
40
41
42
    check_dir_exists(get_config('dataroot') . 'smarty/compile/' . $THEME->basename);
    check_dir_exists(get_config('dataroot') . 'smarty/cache/' . $THEME->basename);
    $smarty->compile_dir   = get_config('dataroot') . 'smarty/compile/' . $THEME->basename;
    $smarty->cache_dir     = get_config('dataroot') . 'smarty/cache/' . $THEME->basename;
43
    $smarty->plugins_dir[] = get_config('libroot') . 'smarty/mahara/';
44

45
    $smarty->assign('THEME', $THEME);
46
47
48
49
    $smarty->assign('WWWROOT', get_config('wwwroot'));

    $theme_list = array();
    foreach ($themepaths['mahara'] as $themepath) {
50
        $theme_list[$themepath] = $THEME->get_url($themepath);
51
52
53
54
55
56
57
    }
    $smarty->assign('THEMELIST', json_encode($theme_list));

    return $smarty;
}


58
59
60
61
62
63
/**
 * This function creates a Smarty object and sets it up for use within our
 * podclass app, setting up some variables.
 *
 * The variables that it sets up are:
 *
64
 * - WWWROOT: The base url for the Mahara system
65
66
67
68
69
 * - USER: The user object
 * - JAVASCRIPT: A list of javascript files to include in the header.  This
 *   list is passed into this function (see below).
 * - HEADERS: An array of any further headers to set.  Each header is just
 *   straight HTML (see below).
70
71
 * - PUBLIC: Set true if this page is a public page
 * - MAINNAV: Array defining the main navigation
72
 *
73
 * @param $javascript A list of javascript includes.  Each include should be just
74
 *                    the name of a file, and reside in js/{filename}
75
76
77
 * @param $headers    A list of additional headers.  These are to be specified as
 *                    actual HTML.
 * @param $strings    A list of language strings required by the javascript code.
78
79
 * @return Smarty
 */
80

81
function &smarty($javascript = array(), $headers = array(), $pagestrings = array(), $extraconfig = array()) {
82
    global $USER, $SESSION, $THEME;
83
84
85
86
87
88
89
90
91
92
93

    if (!is_array($headers)) {
        $headers = array();
    }
    if (!is_array($pagestrings)) {
        $pagestrings = array();
    }
    if (!is_array($extraconfig)) {
        $extraconfig = array();
    }

Martyn Smith's avatar
Martyn Smith committed
94
    $SIDEBLOCKS = array();
95

96
    $smarty = smarty_core();
97
    $smarty->register_function('user_search_form', 'user_search_form');
98

99
    $wwwroot = get_config('wwwroot');
100
    // NOTE: not using jswwwroot - it seems to wreck image paths if you 
101
    // drag them around the wysiwyg editor
102
    $jswwwroot = json_encode($wwwroot);
Martyn Smith's avatar
Martyn Smith committed
103
104

    $theme_list = array();
105
106
107
108
    
    if (function_exists('pieform_get_headdata')) {
        $headers = array_merge($headers, pieform_get_headdata());
    }
109

110
    // Insert the appropriate javascript tags 
111
    $javascript_array = array();
112
    $jsroot = $wwwroot . 'js/';
113

Richard Mansfield's avatar
Richard Mansfield committed
114
    // TinyMCE must be included first for some reason we're not sure about
115
    $checkarray = array(&$javascript, &$headers);
116
    $found_tinymce = false;
117
    foreach ($checkarray as &$check) {
118
119
120
121
        if (($key = array_search('tinymce', $check)) !== false || ($key = array_search('tinytinymce', $check)) !== false) {
            if (!$found_tinymce) {
                $found_tinymce = $check[$key];
                $javascript_array[] = $jsroot . 'tinymce/tiny_mce.js';
122
                $content_css = json_encode($THEME->get_url('style/tinymce.css'));
123
124
                $language = substr(current_language(), 0, 2);
                $execcommand = '';
125
126
                if (isset($extraconfig['tinymcesetup'])) {
                    $execcommand = 'setup: ' . $extraconfig['tinymcesetup'] . ',';
127
                }
128

129
130
                    if ($check[$key] == 'tinymce') {
                        $tinymce_config = <<<EOF
131
    mode: "none",
132
    theme: "advanced",
133
    plugins: "table,emotions,iespell,inlinepopups,paste",
134
    theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,forecolor,backcolor,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,hr,emotions,image,iespell,cleanup,separator,link,unlink,separator,code",
135
    theme_advanced_buttons2 : "bullist,numlist,separator,tablecontrols,separator,cut,copy,paste,pasteword",
136
    theme_advanced_buttons3 : "fontselect,separator,fontsizeselect,separator,formatselect",
137
    theme_advanced_toolbar_location : "top",
138
139
    theme_advanced_toolbar_align : "left",
    //width: '512',
140
EOF;
141
142
143
                    }
                    else {
                        $tinymce_config = <<<EOF
144
    mode: "textareas",
145
146
    editor_selector: 'tinywysiwyg',
    theme: "advanced",
147
    plugins: "fullscreen,inlinepopups",
148
149
    theme_advanced_buttons1 : "bold,italic,underline,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,link,unlink,separator,code,fullscreen",
    theme_advanced_buttons2 : "",
150
151
    theme_advanced_buttons3 : "",
    theme_advanced_toolbar_location : "top",
152
    theme_advanced_toolbar_align : "left",
153
154
155
156
    fullscreen_new_window: true,
    fullscreen_settings: {
        theme: "advanced",
        plugins: "table,emotions,iespell,inlinepopups,paste",
157
        theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,forecolor,backcolor,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,hr,emotions,image,iespell,cleanup,separator,link,unlink,separator,code",
158
159
160
        theme_advanced_buttons2 : "bullist,numlist,separator,tablecontrols,separator,cut,copy,paste,pasteword",
        theme_advanced_buttons3 : "fontselect,separator,fontsizeselect,separator,formatselect"
    },
161
EOF;
162
                }
163

164
                $headers[] = <<<EOF
165
166
167
168
<script type="text/javascript">
tinyMCE.init({
    button_tile_map: true,
    {$tinymce_config}
169
    {$execcommand}
170
    extended_valid_elements : "object[width|height|classid|codebase],param[name|value],embed[src|type|width|height|flashvars|wmode],script[src,type,language],+ul[id|type|compact]",
171
    urlconverter_callback : "custom_urlconvert",
172
    language: '{$language}',
173
    content_css : {$content_css},
174
175
    forced_root_block : "",
    force_p_newlines : false,
176
    apply_source_formatting: false,
177
    //document_base_url: {$jswwwroot},
178
    relative_urls: false
179
});
180
function custom_urlconvert (u, n, e) {
181
  // Don't convert the url on the skype status buttons.
182
183
  if (u.indexOf('skype:') == 0) {
      return u;
184
  }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  var t = tinyMCE.activeEditor, s = t.settings;

  // Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs
  if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0)
      return u;

  // Convert to relative
  if (s.relative_urls)
      return t.documentBaseURI.toRelative(u);

  // Convert to absolute
  u = t.documentBaseURI.toAbsolute(u, s.remove_script_host);

  return u;
199
}
200
201
202
</script>

EOF;
203
204
205
206
207
208
209
                unset($check[$key]);
            }
            else {
                if ($check[$key] != $found_tinymce) {
                    log_warn('Two differently configured tinyMCE instances have been asked for on this page! This is not possible');
                }
                unset($check[$key]);
210
            }
211
        }
212
213
    }

214
    if (get_config('developermode') & DEVMODE_UNPACKEDJS) {
215
        $javascript_array[] = $jsroot . 'MochiKit/MochiKit.js';
216
217
218
219
        $javascript_array[] = $jsroot . 'MochiKit/Position.js';
        $javascript_array[] = $jsroot . 'MochiKit/Color.js';
        $javascript_array[] = $jsroot . 'MochiKit/Visual.js';
        $javascript_array[] = $jsroot . 'MochiKit/DragAndDrop.js';
220
        $javascript_array[] = $jsroot . 'MochiKit/Format.js';
221
222
223
224
    }
    else {
        $javascript_array[] = $jsroot . 'MochiKit/Packed.js';
    }
Martyn Smith's avatar
Martyn Smith committed
225
    $javascript_array[] = $jsroot . 'keyboardNavigation.js';
226

227
    $strings = array();
228
229
230
231
232
233
234
235
236
    foreach ($pagestrings as $k => $v) {
        if (is_array($v)) {
            foreach ($v as $tag) {
                $strings[$tag] = get_raw_string($tag, $k);
            }
        }
        else {
            $strings[$k] = get_raw_string($k, $v);
        }
237
238
    }

239
    $jsstrings = jsstrings();
Martyn Smith's avatar
Martyn Smith committed
240
    $themepaths = themepaths();
241

Richard Mansfield's avatar
Richard Mansfield committed
242
    foreach ($javascript as $jsfile) {
243
244
245
246
        // For now, if there's no path in the js file, assume it's in
        // $jsroot and append '.js' to the name.  Later we may want to
        // ensure all smarty() calls include the full path to the js
        // file, with the proper extension.
247
        if (strpos($jsfile, '/') === false) {
248
            $javascript_array[] = $jsroot . $jsfile . '.js';
249
            if (isset($jsstrings[$jsfile])) {
250
251
252
                foreach ($jsstrings[$jsfile] as $section => $tags) {
                    foreach ($tags as $tag) {
                        $strings[$tag] = get_raw_string($tag, $section);
253
254
255
                    }
                }
            }
Martyn Smith's avatar
Martyn Smith committed
256
257
            if (isset($themepaths[$jsfile])) {
                foreach ($themepaths[$jsfile] as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
258
                    $theme_list[$themepath] = $THEME->get_url($themepath);
Martyn Smith's avatar
Martyn Smith committed
259
260
                }
            }
261
262
        }
        else {
263
            // A .js file with a fully specified path
264
            $javascript_array[] = $wwwroot . $jsfile;
265
266
267
268
269
270
            // If $jsfile is from a plugin (i.e. plugintype/pluginname/js/foo.js)
            // Then get js strings from static function jsstrings in plugintype/pluginname/lib.php 
            $bits = explode('/', $jsfile);
            if (count($bits) == 4) {
                safe_require($bits[0], $bits[1]);
                $pluginclass = generate_class_name($bits[0], $bits[1]);
271
                $name = substr($bits[3], 0, strpos($bits[3], '.js'));
272
273
                if (is_callable(array($pluginclass, 'jsstrings'))) {
                    $tempstrings = call_static_method($pluginclass, 'jsstrings', $name);
274
275
276
                    foreach ($tempstrings as $section => $tags) {
                        foreach ($tags as $tag) {
                            $strings[$tag] = get_raw_string($tag, $section);
277
278
                        }
                    }
Richard Mansfield's avatar
Richard Mansfield committed
279
                }
280
281
282
283
284
285
286
287
288
                if (is_callable(array($pluginclass, 'jshelp'))) {
                    $tempstrings = call_static_method($pluginclass, 'jshelp', $name);
                    foreach ($tempstrings as $section => $tags) {
                        foreach ($tags as $tag) {
                            $strings[$tag . '.help'] = get_help_icon($bits[0], $bits[1], null, null,
                                                                     null, $tag);
                        }
                    }
                }
Martyn Smith's avatar
Martyn Smith committed
289
290
291
                if (is_callable(array($pluginclass, 'themepaths'))) {
                    $tmpthemepaths = call_static_method($pluginclass, 'themepaths', $name);
                    foreach ($tmpthemepaths as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
292
                        $theme_list[$themepath] = $THEME->get_url($themepath);
Martyn Smith's avatar
Martyn Smith committed
293
294
                    }
                }
Martyn Smith's avatar
Martyn Smith committed
295
            }
Martyn Smith's avatar
Martyn Smith committed
296
        }
297
    }
298
299

    $javascript_array[] = $jsroot . 'mahara.js';
300
    if (get_config('developermode') & DEVMODE_DEBUGJS) {
301
        $javascript_array[] = $jsroot . 'debug.js';
302
303
304
305
    }
    if ((get_config('developermode') & DEVMODE_FIREBUGLITE)
        && isset($_SERVER['HTTP_USER_AGENT']) && false === stripos($_SERVER['HTTP_USER_AGENT'], 'gecko')) {
        $javascript_array[] = $jsroot . 'firebug/firebug.js';
306
    }
307

308
309
310
    foreach ($jsstrings['mahara'] as $section => $tags) {
        foreach ($tags as $tag) {
            $strings[$tag] = get_raw_string($tag, $section);
311
312
        }
    }
313
314
    if (isset($extraconfig['themepaths']) && is_array($extraconfig['themepaths'])) {
        foreach ($extraconfig['themepaths'] as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
315
            $theme_list[$themepath] = $THEME->get_url($themepath);
316
317
        }
    }
318

319
    $stringjs = '<script type="text/javascript">';
320
    $stringjs .= 'var strings = ' . json_encode($strings) . ';';
321
322
    $stringjs .= '</script>';

323
    // stylesheet set up - if we're in a plugin also get its stylesheet
Nigel McNie's avatar
Nigel McNie committed
324
    $stylesheets = array_reverse(array_values($THEME->get_url('style/style.css', true)));
325
    if (defined('SECTION_PLUGINTYPE') && defined('SECTION_PLUGINNAME') && SECTION_PLUGINTYPE != 'core') {
Nigel McNie's avatar
Nigel McNie committed
326
        if ($pluginsheets = $THEME->get_url('style/style.css', true, SECTION_PLUGINTYPE . '/' . SECTION_PLUGINNAME)) {
327
328
329
            $stylesheets = array_merge($stylesheets, array_reverse($pluginsheets));
        }
    }
330
    if (defined('ADMIN') || defined('INSTITUTIONALADMIN')) {
331
332
333
        if ($adminsheets = $THEME->get_url('style/admin.css', true)) {
            $stylesheets = array_merge($stylesheets, array_reverse($adminsheets));
        }
334
    }
335
    if (get_config('developermode') & DEVMODE_DEBUGCSS) {
336
337
        $stylesheets[] = get_config('wwwroot') . 'theme/debug.css';
    }
338

339
340
341
    // look for extra stylesheets
    if (isset($extraconfig['stylesheets']) && is_array($extraconfig['stylesheets'])) {
        foreach ($extraconfig['stylesheets'] as $extrasheet) {
342
            if ($sheets = $THEME->get_url($extrasheet, true)) {
Nigel McNie's avatar
Nigel McNie committed
343
                $stylesheets = array_merge($stylesheets, array_reverse(array_values($sheets)));
344
345
346
347
            }
        }
    }

348
    $smarty->assign('STRINGJS', $stringjs);
349

350
    $smarty->assign('STYLESHEETLIST', $stylesheets);
351
352
353
354
    if (!empty($theme_list)) {
        // this gets assigned in smarty_core, but do it again here if it's changed locally
        $smarty->assign('THEMELIST', json_encode(array_merge((array)json_decode($smarty->get_template_vars('THEMELIST')),  $theme_list))); 
    }
355

356

357
358
359
360
    $sitename = get_config('sitename');
    if (!$sitename) {
       $sitename = 'Mahara';
    }
361
    $smarty->assign('sitename', $sitename);
362

Martyn Smith's avatar
Martyn Smith committed
363
    if (defined('TITLE')) {
364
        $smarty->assign('PAGETITLE', TITLE . ' - ' . $sitename);
365
        $smarty->assign('heading', TITLE);
Martyn Smith's avatar
Martyn Smith committed
366
367
    }
    else {
368
        $smarty->assign('PAGETITLE', $sitename);
Martyn Smith's avatar
Martyn Smith committed
369
370
    }

371
372
373
    if (defined('PUBLIC')) {
        $smarty->assign('PUBLIC', true);
    }
374
375
376
    if (defined('ADMIN')) {
        $smarty->assign('ADMIN', true);
    }
377
378
379
    if (defined('INSTITUTIONALADMIN')) {
        $smarty->assign('INSTITUTIONALADMIN', true);
    }
380

381
382
    $smarty->assign('LOGGEDIN', $USER->is_logged_in());
    if ($USER->is_logged_in()) {
383
        $smarty->assign('MAINNAV', main_nav());
384
    }
385
386
    else {
        $smarty->assign('sitedefaultlang', get_string('sitedefault', 'admin') . ' (' . 
387
                        get_string_from_language(get_config('lang'), 'thislanguage') . ')');
388
389
        $smarty->assign('LANGUAGES', get_languages());
    }
390

391
    $smarty->assign_by_ref('USER', $USER);
392
    $smarty->assign('SESSKEY', $USER->get('sesskey'));
393
    $smarty->assign_by_ref('JAVASCRIPT', $javascript_array);
394
    $smarty->assign_by_ref('HEADERS', $headers);
395
396
397
398
399
400
401
402
    if (get_config('siteclosed')) {
        if (get_config('disablelogin')) {
            $smarty->assign('SITECLOSED', get_string('siteclosedlogindisabled', 'mahara', get_config('wwwroot') . 'admin/upgrade.php'));
        }
        else {
            $smarty->assign('SITECLOSED', get_string('siteclosed'));
        }
    }
403

404
405
    if ((!isset($extraconfig['pagehelp']) || $extraconfig['pagehelp'] !== false)
        and $help = has_page_help()) {
406
407
408
        $smarty->assign('PAGEHELPNAME', $help[0]);
        $smarty->assign('PAGEHELPICON', $help[1]);
    }
409
    if (defined('GROUP')) {
410
        require_once('group.php');
411
412
        $group = group_current_group();
        $smarty->assign('GROUP', $group);
413
        $smarty->assign('GROUPNAV', group_get_menu_tabs());
414
        $smarty->assign('PAGEHEADING', hsc($group->name));
415
    }
416

Martyn Smith's avatar
Martyn Smith committed
417
    // ---------- sideblock stuff ----------
418
419
    $sidebars = !isset($extraconfig['sidebars']) || $extraconfig['sidebars'] !== false;
    if ($sidebars && !defined('INSTALLER') && (!defined('MENUITEM') || substr(MENUITEM, 0, 5) != 'admin')) {
Richard Mansfield's avatar
Richard Mansfield committed
420
        if (get_config('installed') && !defined('ADMIN') && !defined('INSTITUTIONALADMIN')) {
421
422
423
424
            $data = site_menu();
            if (!empty($data)) {
                $smarty->assign('SITEMENU', site_menu());
                $SIDEBLOCKS[] = array(
425
                    'name'   => 'linksandresources',
426
427
428
429
430
431
432
                    'weight' => 10,
                    'data'   => $data,
                );
            }
        }

        if ($USER->is_logged_in() && defined('MENUITEM') && substr(MENUITEM, 0, 11) == 'myportfolio') {
Clare Lenihan's avatar
Clare Lenihan committed
433
            $SIDEBLOCKS[] = array(
434
435
436
                'name'   => 'selfsearch',
                'weight' => 0,
                'data'   => array(),
Clare Lenihan's avatar
Clare Lenihan committed
437
            );
438
439
440
441
442
            $SIDEBLOCKS[] = array(
                'name'   => 'mytags',
                'weight' => 0,
                'data'   => mytags_sideblock(),
            );
Clare Lenihan's avatar
Clare Lenihan committed
443
        }
Clare Lenihan's avatar
Clare Lenihan committed
444

Richard Mansfield's avatar
Richard Mansfield committed
445
        if($USER->is_logged_in() && !defined('ADMIN') && !defined('INSTITUTIONALADMIN')) {
446
447
            $SIDEBLOCKS[] = array(
                'name'   => 'profile',
448
                'id'     => 'sb-profile',
449
450
451
                'weight' => -20,
                'data'   => profile_sideblock()
            );
452
453
454
            if (get_config('showonlineuserssideblock')) {
                $SIDEBLOCKS[] = array(
                    'name'   => 'onlineusers',
455
                    'id'     => 'sb-onlineusers',
456
457
458
459
                    'weight' => -10,
                    'data'   => onlineusers_sideblock(),
                );
            }
460
        }
Martyn Smith's avatar
Martyn Smith committed
461

Richard Mansfield's avatar
Richard Mansfield committed
462
463
464
        if(defined('GROUP')) {
            $SIDEBLOCKS[] = array(
                'name'   => 'group',
465
                'id'     => 'sb-groupnav',
Richard Mansfield's avatar
Richard Mansfield committed
466
467
468
469
470
471
                'weight' => -10,
                'data'   => group_sideblock()
            );
        }

        if (!$USER->is_logged_in()) {
472
            $SIDEBLOCKS[] = array(
473
474
                'name'   => 'login',
                'weight' => -10,
475
                'id'     => 'sb-loginbox',
476
477
478
                'data'   => array(
                    'loginform' => auth_generate_login_form(),
                ),
479
480
            );
        }
481

482
483
484
485
486
487
488
489
490
        if (get_config('enablenetworking')) {
            require_once(get_config('docroot') .'api/xmlrpc/lib.php');
            if ($USER->is_logged_in() && $ssopeers = get_service_providers($USER->authinstance)) {
                $SIDEBLOCKS[] = array(
                    'name'   => 'ssopeers',
                    'weight' => 1,
                    'data'   => $ssopeers,
                );
            }
Martyn Smith's avatar
Martyn Smith committed
491
492
        }

493
494
495
496
497
        if (isset($extraconfig['sideblocks']) && is_array($extraconfig['sideblocks'])) {
            foreach ($extraconfig['sideblocks'] as $sideblock) {
                $SIDEBLOCKS[] = $sideblock;
            }
        }
Martyn Smith's avatar
Martyn Smith committed
498

499
500
        usort($SIDEBLOCKS, create_function('$a,$b', 'if ($a["weight"] == $b["weight"]) return 0; return ($a["weight"] < $b["weight"]) ? -1 : 1;'));

501
502
503
504
505
506
507
508
509
        // Place all sideblocks on the right. If this structure is munged 
        // appropriately, you can put blocks on the left. In future versions of 
        // Mahara, we'll make it easy to do this.
        $tmp = $SIDEBLOCKS;
        $SIDEBLOCKS = array(
            'left'  => array(),
            'right' => $tmp,
        );

510
        $smarty->assign('userauthinstance', $SESSION->get('authinstance'));
511
        $smarty->assign('MNETUSER', $SESSION->get('mnetuser'));
512
        $smarty->assign('SIDEBLOCKS', $SIDEBLOCKS);
513
        $smarty->assign('SIDEBARS', $sidebars);
514
515
516

        if ($USER->get('parentuser')) {
            $smarty->assign('USERMASQUERADING', true);
517
            $smarty->assign('masqueradedetails', get_string('youaremasqueradingas', 'mahara', hsc(display_name($USER))));
518
519
520
521
522
            $smarty->assign('becomeyouagain',
                ' <a href="' . hsc($wwwroot) . 'admin/users/changeuser.php?restore=1">'
                . get_string('becomeadminagain', 'admin', $USER->get('parentuser')->name)
                . '</a>');
        }
523
    }
Martyn Smith's avatar
Martyn Smith committed
524

525
526
527
    return $smarty;
}

528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551

/**
 * Manages theme configuration.
 *
 * Does its best to give the user _a_ theme, even if it's not the theme they 
 * want to use (e.g. the theme they want has been uninstalled)
 */
class Theme {

    /**
     * The base name of the theme (the name of the directory in which it lives)
     */
    public $basename = '';

    /**
     * A human-readable version of the theme name
     */
    public $displayname = '';

    /**
     * Which pieform renderer to use by default for all forms
     */
    public $formrenderer = '';

552
553
554
555
556
557
558
559
560
561
    /**
     * Directories where to look for templates by default
     */
    public $templatedirs = array();

    /**
     * Theme inheritance path from this theme to 'raw'
     */
    public $inheritance = array();

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
    /**
     * What unit the left/center/right column widths are in. 'pixels' or 'percent'
     */
    public $columnwidthunits    = '';

    /**
     * Width of the left column. Integer - see $columnwidthunits
     */
    public $leftcolumnwidth     = 256;

    /**
     * Background colour for the left column
     */
    public $leftcolumnbgcolor   = '#fff';

    /**
     * Background colour for the center column
     */
    public $centercolumnbgcolor = '#fff';

    /**
     * Width of the right column. Integer - see $columnwidthunits
     */
    public $rightcolumnwidth    = 256;

    /**
     * Background colour for the right column
     */
    public $rightcolumnbgcolor  = '#fff';


    /**
     * Initialises a theme object based on the theme 'hint' passed.
     *
     * If arg is a string, it's taken to be a theme name. If it's a user 
     * object, we ask it for a theme name. If it's an integer, we pretend 
     * that's a user ID and ask for the theme for that user.
     *
     * If the theme they want doesn't exist, the object is initialised for the 
     * default theme. This means you can initialise one of these for a user
     * and then use it without worrying if the theme exists.
     *
     * @param mixed $arg Theme name, user object or user ID
     */
    public function __construct($arg) {
        if (is_string($arg)) {
            $themename = $arg;
        }
        else if ($arg instanceof User) {
            $themename = $arg->get('theme');
        }
        else if (is_int($arg)) {
            $user = new User();
            $user->find_by_id($arg);
            $themename = $user->get('theme');
        }
        else {
            throw new SystemException("Argument to Theme::__construct was not a theme name, user object or user ID");
        }

        if (!$themename) {
            // Theme to show to when no theme has been suggested
624
625
626
            if (!$themename = get_config('theme')) {
                $themename = 'raw';
            }
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
        }
        $this->init_theme($themename);
    }

    /**
     * Given a theme name, reads in all config and sets fields on this object
     */
    private function init_theme($themename) {
        if (!preg_match('/^[a-zA-Z0-9_-]+$/', $themename)) {
            throw new SystemException("Theme name is in invalid form: '$themename'");
        }

        $this->basename = $themename;

        $themeconfigfile = get_config('docroot') . 'theme/' . $this->basename . '/themeconfig.php';
        if (!is_readable($themeconfigfile)) {
            // We can safely assume that the default theme is installed, users 
            // should never be able to remove it
            $this->basename = 'default';
            $themeconfigfile = get_config('docroot') . 'theme/default/themeconfig.php';
        }

        require($themeconfigfile);

        foreach (get_object_vars($theme) as $key => $value) {
            $this->$key = $value;
        }

        if (!isset($this->displayname)) {
656
            $this->displayname = $this->basename;
657
658
659
660
661
        }
        if (!isset($theme->parent) || !$theme->parent) {
            $theme->parent = 'raw';
        }

662
663
664
        $this->templatedirs[] = get_config('docroot') . 'theme/' . $this->basename . '/templates/';
        $this->inheritance[]  = $this->basename;

665
666
667
668
669
670
671
672
        // Now go through the theme hierarchy assigning variables from the 
        // parent themes
        $currenttheme = $this->basename;
        while ($currenttheme != 'raw') {
            $currenttheme = isset($theme->parent) ? $theme->parent : 'raw';
            $parentconfigfile = get_config('docroot') . 'theme/' . $currenttheme . '/themeconfig.php';
            require($parentconfigfile);
            foreach (get_object_vars($theme) as $key => $value) {
673
                if (!isset($this->$key) || !$this->$key) {
674
675
676
                    $this->$key = $value;
                }
            }
677
678
            $this->templatedirs[] = get_config('docroot') . 'theme/' . $currenttheme . '/templates/';
            $this->inheritance[]  = $currenttheme;
679
680
681
        }
    }

682
683
684
    /**
     * stuff
     */
685
686
    public function get_url($filename, $all=false, $plugindirectory='') {
        return $this->_get_path($filename, $all, $plugindirectory, get_config('wwwroot'));
687
688
    }

689
690
    public function get_path($filename, $all=false, $plugindirectory='') {
        return $this->_get_path($filename, $all, $plugindirectory, get_config('docroot'));
691
692
    }

693
    private function _get_path($filename, $all, $plugindirectory, $returnprefix) {
694
        $list = array();
695
        $plugindirectory = ($plugindirectory && substr($plugindirectory, -1) != DIRECTORY_SEPARATOR) ? $plugindirectory . DIRECTORY_SEPARATOR : $plugindirectory;
696
697

        foreach ($this->inheritance as $themedir) {
698
            if (is_readable(get_config('docroot') . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename)) {
699
                if ($all) {
700
                    $list[$themedir] = $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
701
702
                }
                else {
703
                    return $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
704
705
706
707
708
709
710
711
                }
            }
        }
        if ($all) {
            return $list;
        }

        $extra = '';
712
713
        if ($plugindirectory) {
            $extra = ", plugindir $plugindirectory";
714
715
        }
        log_debug("Missing file in theme {$this->basename}{$extra}: $filename");
716
        return $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
717
718
    }

719
720
721
}


722
723
/** 
 * Returns the lists of strings used in the .js files
724
 * @return array                   
725
726
 */

727
function jsstrings() {
Martyn Smith's avatar
Martyn Smith committed
728
    return array(
729
730
731
       'mahara' => array(                        // js file
            'mahara' => array(                   // section
                'namedfieldempty',               // string name
732
                'processing',
733
734
735
                'requiredfieldempty',
                'unknownerror',
                'loading',
Martyn Smith's avatar
Martyn Smith committed
736
                'showtags',
737
738
                'unreadmessages',
                'unreadmessage',
739
740
                'pendingfriend',
                'pendingfriends',
741
                'couldnotgethelp',
742
743
744
745
746
747
                'password',
                'username',
                'login',
                'sessiontimedout',
                'loginfailed',
                'home',
748
                'youhavenottaggedanythingyet',
749
            ),
750
751
        ),
        'tablerenderer' => array(
752
753
754
755
756
757
            'mahara' => array(
                'firstpage',
                'nextpage',
                'prevpage',
                'lastpage',
            )
758
        ),
759
        'friends' => array(
760
            'group' => array(
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
                'confirmremovefriend',
                'seeallviews',
                'noviewstosee',
                'sendmessage',
                'whymakemeyourfriend',
                'approverequest',
                'denyrequest',
                'pending',
                'removefromfriendslist',
                'views',
                'trysearchingforfriends',
                'nobodyawaitsfriendapproval',
                'sendfriendrequest',
                'addtomyfriends',
                'friendshiprequested',
                'userdoesntwantfriends',
                'existingfriend',
                'nosearchresultsfound',
779
                'reason',
780
                'requestfriendship',
781
                'cancel',
782
783
            ),
        ),
784
785
786
        'views' => array(
            'view' => array(
                'confirmdeleteblockinstance',
787
                'blocksinstructionajax',
788
                'Configure',
789
790
            ),
        ),
791
792
793
794
795
796
797
798
799
        'adminusersearch' => array(
            'admin' => array(
                'suspenduser',
                'suspensionreason',
            ),
            'mahara' => array(
                'cancel',
            ),
        ),
800
801
802
803
804
805
806
807
808
809
        'feedbacklist' => array(
            'view' => array(
                'feedbackattachmessage',
                'makeprivate',
                'thisfeedbackisprivate',
                'thisfeedbackispublic',
                'attachment',
                'nopublicfeedback',
            ),
        ),
Martyn Smith's avatar
Martyn Smith committed
810
811
812
    );
}

Martyn Smith's avatar
Martyn Smith committed
813
function themepaths() {
814
815
816
817
818
819
820
821
822

    static $paths;
    if (empty($paths)) {
        $paths = array(
            'mahara' => array(
                'images/icon_close.gif',
                'images/failure.gif',
                'images/loading.gif',
                'images/success.gif',
823
                'images/icon_problem.gif',
824
                'images/icon_help.gif',
825
                'style/js.css',
826
827
828
829
            ),
        );
    }
    return $paths;
Martyn Smith's avatar
Martyn Smith committed
830
831
}

832
833
834
835
836
837
/** 
 * Takes an array of string identifiers and returns an array of the
 * corresponding strings, quoted for use in inline javascript here
 * docs.
 */

838
839
840
841
function quotestrings($strings) {
    $qstrings = array();
    foreach ($strings as $section => $tags) {
        foreach ($tags as $tag) {
842
            $qstrings[$tag] = json_encode(get_string($tag, $section));
843
        }
844
    }
845
    return $qstrings;
846
847
}

848
849
850
851
852
853
854
/** 
 * This function sets up and caches info about the current selected theme
 * contains inheritance path (used for locating images) and template dirs
 * and potentially more stuff later ( like mime header to send (html vs xhtml))
 * @return object
 */
function theme_setup() {
855
856
857
    global $THEME;
    log_warn("theme_setup() is deprecated - please use the global \$THEME object instead");
    return $THEME;
858
859
860
861
862
863
864
865
}

/** 
 * This function returns the full url to an image
 * Always use it to get image urls
 * @param $imagelocation path to image relative to theme/$theme/static/
 * @param $pluginlocation path to plugin relative to docroot
 */
866
function theme_get_url($location, $pluginlocation='', $all = false) {
867
868
869
870
871
872
    global $THEME;
    log_warn("theme_get_url() is deprecated: Use \$THEME->get_url() instead");
    $plugintype = $pluginname = '';
    if ($pluginlocation) {
        list($plugintype, $pluginname) = explode('/', $pluginlocation);
        $pluginname = substr($pluginname, 0, -1);
873
    }
874
    return $THEME->get_url($location, $all, $plugintype, $pluginname);
875
876
}

877
878
879
880
881
882
/** 
 * This function returns the full path to an image
 * Always use it to get image paths
 * @param $imagelocation path to image relative to theme/$theme/static/
 * @param $pluginlocation path to plugin relative to docroot
 */
883
function theme_get_path($location, $pluginlocation='', $all=false) {
884
885
886
887
888
889
    global $THEME;
    log_warn("theme_get_path() is deprecated: Use \$THEME->get_path() instead");
    $plugintype = $pluginname = '';
    if ($pluginlocation) {
        list($plugintype, $pluginname) = explode('/', $pluginlocation);
        $pluginname = substr($pluginname, 0, -1);
890
    }
891
    return $THEME->get_path($location, $all, $plugintype, $pluginname);
892
893
}

894
895
896
897
898
/**
 * This function sends headers suitable for all JSON returning scripts.
 *
 */
function json_headers() {
899
    // @todo Catalyst IT Ltd
900
901
    // header('Content-type: text/x-json');
    header('Content-type: text/plain');
Martyn Smith's avatar
Martyn Smith committed
902
    header('Pragma: no-cache');
903
904
}

Richard Mansfield's avatar
Richard Mansfield committed
905
/**
906
 * This function sends a JSON message, and ends the script.
Richard Mansfield's avatar
Richard Mansfield committed
907
 *
908
909
910
911
912
913
914
915
 * Scripts receiving replies will recieve a JSON array with two fields:
 *
 *  - error: True or false depending on whether the request was successful
 *  - message: JSON data representing a message sent back from the script
 *
 * @param boolean $error   Whether the script ended in an error or not
 * @param string  $message A message to pass back to the user, can be an
 *                         array of JSON data
Richard Mansfield's avatar
Richard Mansfield committed
916
 */
917
function json_reply($error, $message, $returncode=0) {
Richard Mansfield's avatar
Richard Mansfield committed
918
    json_headers();
919
    echo json_encode(array('error' => $error, 'message' => $message, 'returnCode' => $returncode));
920
    perf_to_log();
Richard Mansfield's avatar
Richard Mansfield committed
921
922
923
    exit;
}

924
function _param_retrieve($name) {
925
926
927
928
929
930
931
    // prefer post
    if (isset($_POST[$name])) {
        $value = $_POST[$name];
    } 
    else if (isset($_GET[$name])) {
        $value = $_GET[$name];
    }
932
    else if (func_num_args() == 2) {
933
934
935
        $php_work_around = func_get_arg(1);
        return array($php_work_around, true);
    }
936
    else {
937
938
939
        throw new ParameterException("Missing parameter '$name' and no default supplied");
    }

940
    return array($value, false);
941
942
}

Martyn Smith's avatar
Martyn Smith committed
943
944
945
946
947
948
949
950
951
952
953
/**
 * This function returns a GET or POST parameter with optional default.  If the
 * default isn't specified and the parameter hasn't been sent, a
 * ParameterException exception is thrown
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
 * @return string The value of the parameter
 *
 */
Martyn Smith's avatar
Martyn Smith committed
954
function param_variable($name) {
955
956
957
    $args = func_get_args();
    list ($value) = call_user_func_array('_param_retrieve', $args);
    return $value;
Martyn Smith's avatar
Martyn Smith committed
958
959
960
961
962
963
964
965
966
967
968
}

/**
 * This function returns a GET or POST parameter as an integer with optional
 * default.  If the default isn't specified and the parameter hasn't been sent,
 * a ParameterException exception is thrown. Likewise, if the parameter isn't a
 * valid integer, a ParameterException exception is thrown
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
Nigel McNie's avatar
Nigel McNie committed
969
 * @return int The value of the parameter
Martyn Smith's avatar
Martyn Smith committed
970
971
 *
 */
Martyn Smith's avatar
Martyn Smith committed
972
function param_integer($name) {
973
974
975
976
977
978
    $args = func_get_args();

    list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);

    if ($defaultused) {
        return $value;
Martyn Smith's avatar
Martyn Smith committed
979
980
981
982
983
    }

    if (preg_match('/^\d+$/',$value)) {
        return (int)$value;
    }
984
985
986
    else if ($value == '' && isset($args[1])) {
        return $args[1];
    }
Martyn Smith's avatar
Martyn Smith committed
987

988
    throw new ParameterException("The '$name' parameter is not an integer");
Martyn Smith's avatar
Martyn Smith committed
989
990
}

Martyn Smith's avatar
Martyn Smith committed
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
/**
 * This function returns a GET or POST parameter as an alpha string with optional
 * default.  If the default isn't specified and the parameter hasn't been sent,
 * a ParameterException exception is thrown. Likewise, if the parameter isn't a
 * valid alpha string, a ParameterException exception is thrown
 *
 * Valid characters are a-z and A-Z
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
 * @return string The value of the parameter
 *
 */
function param_alpha($name) {
1006
1007
1008
1009
1010
1011
    $args = func_get_args();

    list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);

    if ($defaultused) {
        return $value;
Martyn Smith's avatar
Martyn Smith committed
1012
1013
    }

Richard Mansfield's avatar
Richard Mansfield committed
1014
    if (preg_match('/^[a-zA-Z]+$/',$value)) {
Martyn Smith's avatar
Martyn Smith committed
1015
1016
1017
        return $value;
    }

1018
    throw new ParameterException("The '$name' parameter is not alphabetical only");
Martyn Smith's avatar
Martyn Smith committed
1019
1020
}

1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
/**
 * This function returns a GET or POST parameter as an alphanumeric string with optional
 * default.  If the default isn't specified and the parameter hasn't been sent,
 * a ParameterException exception is thrown. Likewise, if the parameter isn't a
 * valid alpha string, a ParameterException exception is thrown
 *
 * Valid characters are a-z and A-Z and 0-9
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
 * @return string The value of the parameter
 *
 */
function param_alphanum($name) {
    $args = func_get_args();

    list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);

    if ($defaultused) {
        return $value;
    }

    if (preg_match('/^[a-zA-Z0-9]+$/',$value)) {
        return $value;
    }

1048
    throw new ParameterException("The '$name' parameter is not alphanumeric only");
1049
1050
}

1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
/**
 * This function returns a GET or POST parameter as an alphanumeric string with optional
 * default.  If the default isn't specified and the parameter hasn't been sent,
 * a ParameterException exception is thrown. Likewise, if the parameter isn't a
 * valid alpha string, a ParameterException exception is thrown
 *
 * Valid characters are a-z and A-Z and 0-9 and _ and - and .
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
 * @return string The value of the parameter
 *
 */
function param_alphanumext($name) {
    $args = func_get_args();

    list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);

    if ($defaultused) {
        return $value;
    }

    if (preg_match('/^[a-zA-Z0-9_.-]+$/',$value)) {
        return $value;
    }

Nigel McNie's avatar