Proyectos de Subversion Moodle

Rev

Rev 256 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Theme functions.
19
 *
20
 * @package   theme_universe
21
 * @copyright 2023 Marcin Czaja (https://rosea.io)
22
 * @license   Commercial https://themeforest.net/licenses
23
 */
24
 
25
/**
26
 * Get theme setting
27
 *
28
 * @param string $setting
29
 * @param bool $format
30
 * @return string
31
 */
126 ariadna 32
function theme_universe_get_setting($setting, $format = false)
33
{
1 efrain 34
    $theme = theme_config::load('universe');
35
 
36
    if (empty($theme->settings->$setting)) {
37
        return false;
38
    }
39
 
40
    if (!$format) {
41
        return $theme->settings->$setting;
42
    }
43
 
44
    if ($format === 'format_text') {
45
        return format_text($theme->settings->$setting, FORMAT_PLAIN);
46
    }
47
 
48
    if ($format === 'format_html') {
49
        return format_text($theme->settings->$setting, FORMAT_HTML, array('trusted' => true, 'noclean' => true));
50
    }
51
 
52
    return format_string($theme->settings->$setting);
53
}
54
 
1287 ariadna 55
function theme_universe_themedir()
56
{
57
    global $CFG;
58
 
59
    $teme_dir = '/theme';
60
 
61
    if (isset($CFG->themedir)) {
62
        $teme_dir = $CFG->themedir;
63
        $teme_dir = str_replace($CFG->dirroot, '', $CFG->themedir);
64
    }
65
 
66
    return $teme_dir;
67
}
68
 
1 efrain 69
/**
70
 * Post process the CSS tree.
71
 *
72
 * @param string $tree The CSS tree.
73
 * @param theme_config $theme The theme config object.
74
 */
126 ariadna 75
function theme_universe_css_tree_post_processor($tree, $theme)
76
{
1 efrain 77
    debugging('theme_universe_css_tree_post_processor() is deprecated. Required' .
78
        'prefixes for Bootstrap are now in theme/universe/scss/moodle/prefixes.scss');
79
    $prefixer = new theme_universe\autoprefixer($tree);
80
    $prefixer->prefix();
81
}
82
 
83
/**
84
 * Get the current user preferences that are available
85
 *
86
 * @return array[]
87
 */
126 ariadna 88
function theme_universe_user_preferences(): array
89
{
1 efrain 90
    return [
91
        'drawer-open-block' => [
92
            'type' => PARAM_BOOL,
93
            'null' => NULL_NOT_ALLOWED,
94
            'default' => false,
95
            'permissioncallback' => [core_user::class, 'is_current_user'],
96
        ],
97
        'drawer-open-index' => [
98
            'type' => PARAM_BOOL,
99
            'null' => NULL_NOT_ALLOWED,
100
            'default' => true,
101
            'permissioncallback' => [core_user::class, 'is_current_user'],
102
        ],
103
        'darkmode-on' => [
104
            'type' => PARAM_BOOL,
105
            'null' => NULL_NOT_ALLOWED,
106
            'default' => false,
107
            'permissioncallback' => [core_user::class, 'is_current_user'],
108
        ],
109
        'sidepre-open' => [
110
            'type' => PARAM_BOOL,
111
            'null' => NULL_NOT_ALLOWED,
112
            'default' => true,
113
            'permissioncallback' => [core_user::class, 'is_current_user'],
114
        ],
115
    ];
116
}
117
 
118
/**
119
 * Inject additional SCSS.
120
 *
121
 * @param theme_config $theme The theme config object.
122
 * @return string
123
 */
126 ariadna 124
function theme_universe_get_extra_scss($theme)
125
{
1 efrain 126
    $content = '';
127
 
128
    // Sets the login background image.
129
    // Check login layout, only layout #1 has background image.
130
    $loginlayout = theme_universe_get_setting('setloginlayout');
131
    $loginlayoutimg = false;
132
 
133
    if ($loginlayout == 1 || $loginlayout == 4 || $loginlayout == 5) {
134
        $loginlayoutimg = true;
135
    }
136
    if ($loginlayout == 2 || $loginlayout == 3) {
137
        $loginlayoutimg = false;
138
    } else {
139
        $loginlayoutimg = false;
140
    }
141
 
142
    $loginbackgroundimageurl = $theme->setting_file_url('loginbg', 'loginbg');
143
    if ($loginlayout == 1) {
144
        if (!empty($loginbackgroundimageurl)) {
145
            $content .= 'body.path-login { ';
146
            $content .= "background-image: url('$loginbackgroundimageurl')!important; background-size: cover!important;";
147
            $content .= ' }';
148
        }
149
    }
150
 
151
    $forcefwvideo = theme_universe_get_setting('forcefwvideo');
152
    if ($forcefwvideo == 1) {
153
        $content .= '.mediaplugin.mediaplugin_videojs div[style*="max-width"] {margin-left:auto;margin-right:auto;
154
            width: 100%; max-width: 100% !important;}';
155
        $content .= '.mediaplugin div {max-width:100%!important;}';
156
    }
157
 
158
    // Always return the background image with the scss when we have it.
159
    return !empty($theme->settings->scss) ? $theme->settings->scss . ' ' . $content : $content;
160
}
161
 
162
/**
163
 * Serves any files associated with the theme settings.
164
 *
165
 * @param stdClass $course
166
 * @param stdClass $cm
167
 * @param context $context
168
 * @param string $filearea
169
 * @param array $args
170
 * @param bool $forcedownload
171
 * @param array $options
172
 * @return bool
173
 */
126 ariadna 174
function theme_universe_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array())
175
{
1 efrain 176
    if ($context->contextlevel == CONTEXT_SYSTEM) {
177
        $theme = theme_config::load('universe');
178
        // By default, theme files must be cache-able by both browsers and proxies.
179
        if (!array_key_exists('cacheability', $options)) {
180
            $options['cacheability'] = 'public';
181
        }
182
        if ($filearea === 'hvp') {
183
            return theme_universe_serve_hvp_css($args[1], $theme);
184
        }
185
        if ($filearea === 'favicon') {
186
            return $theme->setting_file_serve('favicon', $args, $forcedownload, $options);
187
        } else if ($filearea === 'logo') {
188
            return $theme->setting_file_serve('logo', $args, $forcedownload, $options);
189
        } else if ($filearea === 'loginbg') {
190
            return $theme->setting_file_serve('loginbg', $args, $forcedownload, $options);
191
        } else if ($filearea === 'customloginlogo') {
192
            return $theme->setting_file_serve('customloginlogo', $args, $forcedownload, $options);
193
        } else if ($filearea === 'customlogo') {
194
            return $theme->setting_file_serve('customlogo', $args, $forcedownload, $options);
195
        } else if ($filearea === 'customdmlogo') {
196
            return $theme->setting_file_serve('customdmlogo', $args, $forcedownload, $options);
197
        } else if ($filearea === 'customsidebarlogo') {
198
            return $theme->setting_file_serve('customsidebarlogo', $args, $forcedownload, $options);
199
        } else if ($filearea === 'customsidebardmlogo') {
200
            return $theme->setting_file_serve('customsidebardmlogo', $args, $forcedownload, $options);
201
        } else if ($filearea === 'fontfiles') {
202
            return $theme->setting_file_serve('fontfiles', $args, $forcedownload, $options);
203
        } else if ($filearea === 'universesettingsimgs') {
204
            return $theme->setting_file_serve('universesettingsimgs', $args, $forcedownload, $options);
205
        } else if (preg_match("/^block1slideimg[1-9][0-9]?$/", $filearea) !== false) {
206
            return $theme->setting_file_serve($filearea, $args, $forcedownload, $options);
207
        } else if (preg_match("/^block5itemimg[1-9][0-9]?$/", $filearea) !== false) {
208
            return $theme->setting_file_serve($filearea, $args, $forcedownload, $options);
209
        } else if ($filearea === 'block2videoposter') {
210
            return $theme->setting_file_serve('block2videoposter', $args, $forcedownload, $options);
211
        } else if ($filearea === 'block2img') {
212
            return $theme->setting_file_serve('block2img', $args, $forcedownload, $options);
213
        } else if ($filearea === 'block2videomp4') {
214
            return $theme->setting_file_serve('block2videomp4', $args, $forcedownload, $options);
215
        } else if ($filearea === 'block2videowebm') {
216
            return $theme->setting_file_serve('block2videowebm', $args, $forcedownload, $options);
217
        } else if ($filearea === 'footerbgimg') {
218
            return $theme->setting_file_serve('footerbgimg', $args, $forcedownload, $options);
219
        } else {
220
            send_file_not_found();
221
        }
222
    }
223
}
224
 
225
/**
226
 * Get the URL of files from theme settings.
227
 *
228
 * @param $setting
229
 * @param $filearea
230
 * @param $theme
231
 * @return array|false|string|string[]|null
232
 * @throws dml_exception
233
 */
126 ariadna 234
function theme_universe_setting_file_url($setting, $filearea, $theme)
235
{
1 efrain 236
    global $CFG;
237
 
238
    $component = 'theme_universe';
239
    $itemid = 0;
240
    $filepath = $theme->settings->$filearea;
241
 
242
    if (empty($filepath)) {
243
        return false;
244
    }
245
    $syscontext = context_system::instance();
246
 
247
    $url = moodle_url::make_file_url("$CFG->wwwroot/pluginfile.php", "/$syscontext->id/$component/$filearea/$itemid" . $filepath);
248
 
249
    // Now this is tricky because the we can not hardcode http or https here, lets use the relative link.
250
    // Note: unfortunately moodle_url does not support //urls yet.
251
 
252
    $url = preg_replace('|^https?://|i', '//', $url->out(false));
253
 
254
    return $url;
255
}
256
 
257
/**
258
 * Returns the main SCSS content.
259
 *
260
 * @param theme_config $theme The theme config object.
261
 * @return string
262
 */
126 ariadna 263
function theme_universe_get_main_scss_content($theme)
264
{
1 efrain 265
    global $CFG;
266
 
267
    $scss = '';
268
    $filename = !empty($theme->settings->preset) ? $theme->settings->preset : null;
269
    $fs = get_file_storage();
270
 
271
    $context = context_system::instance();
272
    if ($filename == 'default.scss') {
273
        $scss .= file_get_contents($CFG->dirroot . '/theme/universe/scss/preset/default.scss');
274
    } else if ($filename == 'plain.scss') {
275
        $scss .= file_get_contents($CFG->dirroot . '/theme/universe/scss/preset/plain.scss');
276
    } else if ($filename && ($presetfile = $fs->get_file($context->id, 'theme_universe', 'preset', 0, '/', $filename))) {
277
        $scss .= $presetfile->get_content();
278
    } else {
279
        // Safety fallback - maybe new installs etc.
280
        $scss .= file_get_contents($CFG->dirroot . '/theme/universe/scss/preset/default.scss');
281
    }
282
 
283
    return $scss;
284
}
285
 
286
/**
287
 * Get compiled css.
288
 *
289
 * @return string compiled css
290
 */
126 ariadna 291
function theme_universe_get_precompiled_css()
292
{
1 efrain 293
    global $CFG;
294
    return file_get_contents($CFG->dirroot . '/theme/universe/style/moodle.css');
295
}
296
 
297
/**
298
 * Get SCSS to prepend.
299
 *
300
 * @param theme_config $theme The theme config object.
301
 * @return array
302
 */
126 ariadna 303
function theme_universe_get_pre_scss($theme)
304
{
1 efrain 305
    global $CFG;
306
 
307
    $scss = '';
308
    $configurable = [
309
        // Config key => [variableName, ...].
310
        'colorloginbgtext' => ['colorloginbgtext'],
311
        // Blocks.
312
        'block1sliderwrapperbg' => ['block1-wrapper-bg'],
313
        'block2wrapperbg' => ['block2-wrapper-bg'],
314
        'block3wrapperbg' => ['block3-wrapper-bg'],
315
        'block4sliderwrapperbg' => ['block4-wrapper-bg'],
316
        // Customization.
317
        'fontweightheadings' => ['headings-font-weight'],
318
        'fontbody' => ['font-family-base'],
319
        'fontweightregular' => ['font-weight-normal'],
320
        'fontweightmedium' => ['font-weight-medium'],
321
        'fontweightbold' => ['font-weight-bold'],
322
        'fontheadings' => ['fontheadings'],
323
        // 'coursedescwidth' => ['coursedescwidth'],
324
        // 'incoursedescwidth' => ['incoursedescwidth'],
325
        // Text.
326
        'colorbody' => ['body-color'],
327
        'colorbodysecondary' => ['body-color-secondary'],
328
        'colorbodylight' => ['body-color-light'],
329
        'colorlink' => ['link-color'],
330
        'colorlinkhover' => ['link-color-hover'],
331
        // Grays.
332
        'white' => ['white'],
333
        'black' => ['black'],
334
        'colorgray100' => ['gray-100'],
335
        'colorgray200' => ['gray-200'],
336
        'colorgray300' => ['gray-300'],
337
        'colorgray400' => ['gray-400'],
338
        'colorgray500' => ['gray-500'],
339
        'colorgray600' => ['gray-600'],
340
        'colorgray700' => ['gray-700'],
341
        'colorgray800' => ['gray-800'],
342
        'colorgray900' => ['gray-900'],
343
        // Primary.
344
        'colorprimary100' => ['primary-color-100'],
345
        'colorprimary200' => ['primary-color-200'],
346
        'colorprimary300' => ['primary-color-300'],
347
        'colorprimary400' => ['primary-color-400'],
348
        'colorprimary500' => ['primary-color-500'],
349
        'colorprimary600' => ['primary-color-600'],
350
        'colorprimary700' => ['primary-color-700'],
351
        'colorprimary800' => ['primary-color-800'],
352
        'colorprimary900' => ['primary-color-900'],
353
        // Others.
354
        'colorbodybg' => ['body-bg'],
355
        'colorborder' => ['border-color'],
356
        //'colorcoursecardmask' => ['course-card-shadow-color'],
357
        // Topbar.
358
        'topbarheight' => ['navbar-height'],
359
        'colortopbarbg1' => ['topbar-bg'],
360
        'colortopbarbg2' => ['topbar-bg-2'],
361
        'dmcolortopbarbg1' => ['topbar-bg'],
362
        'dmcolortopbarbg2' => ['dm-topbar-bg-2'],
363
        'colortopbartext' => ['dm-topbar-text'],
364
        'colortopbarlink' => ['topbar-link'],
365
        'colortopbarlinkhover' => ['topbar-link-hover'],
366
        'colortopbarbtntext' => ['topbar-btn-text'],
367
        'colortopbarbtnhover' => ['topbar-btn-hover'],
368
        'colortopbarbtnhovertext' => ['topbar-btn-hover-text'],
369
        // Buttons.
370
        'btnborderradius' => ['btn-border-radius'],
371
        // Sidebar.
372
        'colordrawerbg' => ['drawer-bg'],
373
        'colordrawertext' => ['drawer-text'],
374
        'colordrawernavcontainer' => ['drawer-nav-container'],
375
        'colordrawernavbtntext' => ['drawer-nav-btn-text'],
376
        'colordrawernavbtnicon' => ['drawer-nav-btn-icon'],
377
        'colordrawernavbtntexth' => ['drawer-nav-btn-text-hover'],
378
        'colordrawernavbtniconh' => ['drawer-nav-btn-icon-hover'],
379
        'colordrawernavbtnbgh' => ['drawer-nav-btn-bg-hover'],
380
        'colordrawernavbtntextlight' => ['drawer-nav-btn-text-light'],
381
        'colordrawerscrollbar' => ['drawer-scroll-bg-track'],
382
        'colordrawerlink' => ['drawer-link'],
383
        'colordrawerlinkh' => ['drawer-link-h'],
384
        'colordrawernavboxbg' => ['drawer-nav-box-bg'],
385
        'colordrawernavbtnicon' => ['drawer-nav-btn-icon'],
386
        // Footer.
387
        'colorfooterbg' => ['footer-bg'],
388
        'colorfooterborder' => ['footer-border'],
389
        'colorfootertext' => ['footer-text-color'],
390
        'colorfooterlink' => ['footer-link-color'],
391
        'colorfooterlinkhover' => ['footer-link-color-hover'],
392
        'colorcoursecardmask' => ['course-card-mask-color'],
393
        'showcolorcoursecardmask' => ['showcolorcoursecardmask'],
394
        // Login.
395
        'loginbgcolor' => ['login-bgcolor'],
396
        // Icon Colors.
397
        'iconadministration' => ['icon-color-administraion'],
398
        'iconassessment' => ['icon-color-assessment'],
399
        'iconcolleboration' => ['icon-color-collaboration'],
400
        'iconcommunication' => ['icon-color-communication'],
401
        'iconcontent' => ['icon-color-content'],
402
        'iconinterface' => ['icon-color-interface']
403
    ];
404
 
405
    // Prepend variables first.
406
    foreach ($configurable as $configkey => $targets) {
407
        $value = isset($theme->settings->{$configkey}) ? $theme->settings->{$configkey} : null;
408
        if (empty($value)) {
409
            continue;
410
        }
411
        array_map(function ($target) use (&$scss, $value) {
412
            $scss .= '$' . $target . ': ' . $value . ";\n";
413
        }, (array) $targets);
414
    }
415
 
416
    // Prepend pre-scss.
417
    if (!empty($theme->settings->scsspre)) {
418
        $scss .= $theme->settings->scsspre;
419
    }
420
 
421
    return $scss;
422
}
423
 
424
/**
425
 * Build the guest access hint HTML code.
426
 *
427
 * @param int $courseid The course ID.
428
 * @return string.
429
 */
126 ariadna 430
function theme_universe_get_course_guest_access_hint($courseid)
431
{
1 efrain 432
    global $CFG;
433
    require_once($CFG->dirroot . '/enrol/self/lib.php');
434
 
435
    $html = '';
436
    $instances = enrol_get_instances($courseid, true);
437
    $plugins = enrol_get_plugins(true);
438
    foreach ($instances as $instance) {
439
        if (!isset($plugins[$instance->enrol])) {
440
            continue;
441
        }
442
        $plugin = $plugins[$instance->enrol];
443
        if ($plugin->show_enrolme_link($instance)) {
444
            $html = html_writer::tag('div', get_string(
445
                'showhintcourseguestaccesslink',
446
                'theme_universe',
447
                array('url' => $CFG->wwwroot . '/enrol/index.php?id=' . $courseid)
448
            ));
449
            break;
450
        }
451
    }
452
 
453
    return $html;
454
}
455
 
456
/**
457
 * Build the course page information banners HTML code.
458
 * This function evaluates and composes all information banners which may appear on a course page below the full header.
459
 *
460
 * @return string.
461
 */
126 ariadna 462
function theme_universe_get_course_information_banners()
463
{
1 efrain 464
    global $CFG, $COURSE, $PAGE, $USER, $OUTPUT;
465
 
466
    // Require user library.
467
    require_once($CFG->dirroot . '/user/lib.php');
468
 
469
    // Initialize HTML code.
470
    $html = '';
471
 
472
    // Check if user is admin, teacher or editing teacher.
473
    if (
474
        user_has_role_assignment($USER->id, '1') ||
475
        user_has_role_assignment($USER->id, '2') ||
476
        user_has_role_assignment($USER->id, '3') ||
477
        user_has_role_assignment($USER->id, '4')
478
    ) {
479
        $allowtoshowhint = true;
480
    } else {
481
        $allowtoshowhint = false;
482
    }
483
 
484
    // If the setting showhintcoursehidden is set and the visibility of the course is hidden and
485
    // a hint for the visibility will be shown.
486
    if (
487
        get_config('theme_universe', 'showhintcoursehidden') == 1
488
        && $allowtoshowhint == true
489
        && $PAGE->has_set_url()
490
        && $PAGE->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)
491
        && $COURSE->visible == false
492
    ) {
493
 
494
        // Prepare template context.
495
        $templatecontext = array('courseid' => $COURSE->id);
496
 
497
        // If the user has the capability to change the course settings, an additional link to the course settings is shown.
498
        if (has_capability('moodle/course:update', context_course::instance($COURSE->id))) {
499
            $templatecontext['showcoursesettingslink'] = true;
500
        } else {
501
            $templatecontext['showcoursesettingslink'] = false;
502
        }
503
 
504
        // Render template and add it to HTML code.
505
        $html .= $OUTPUT->render_from_template('theme_universe/course-hint-hidden', $templatecontext);
506
    }
507
 
508
    // If the setting showhintcourseguestaccess is set and the user is accessing the course with guest access,
509
    // a hint for users is shown.
510
    // We also check that the user did not switch the role. This is a special case for roles that can fully access the course
511
    // without being enrolled. A role switch would show the guest access hint additionally in that case and this is not
512
    // intended.
513
    if (
514
        get_config('theme_universe', 'showhintcourseguestaccess') == 1
515
        && is_guest(\context_course::instance($COURSE->id), $USER->id)
516
        && $PAGE->has_set_url()
517
        && $PAGE->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)
518
        && !is_role_switched($COURSE->id)
519
    ) {
520
 
521
        // Require self enrolment library.
522
        require_once($CFG->dirroot . '/enrol/self/lib.php');
523
 
524
        // Prepare template context.
525
        $templatecontext = array(
526
            'courseid' => $COURSE->id,
527
            'role' => role_get_name(get_guest_role())
528
        );
529
 
530
        // Search for an available self enrolment link in this course.
531
        $templatecontext['showselfenrollink'] = false;
532
        $instances = enrol_get_instances($COURSE->id, true);
533
        $plugins = enrol_get_plugins(true);
534
        foreach ($instances as $instance) {
535
            // If the enrolment plugin isn't enabled currently, skip it.
536
            if (!isset($plugins[$instance->enrol])) {
537
                continue;
538
            }
539
 
540
            // Remember the enrolment plugin.
541
            $plugin = $plugins[$instance->enrol];
542
 
543
            // If there is a self enrolment link.
544
            if ($plugin->show_enrolme_link($instance)) {
545
                $templatecontext['showselfenrollink'] = true;
546
                break;
547
            }
548
        }
549
 
550
        // Render template and add it to HTML code.
551
        $html .= $OUTPUT->render_from_template('theme_universe/course-hint-guestaccess', $templatecontext);
552
    }
553
 
554
    // If the setting showhintcourseselfenrol is set, a hint for users is shown that the course allows unrestricted self
555
    // enrolment. This hint is only shown if the course is visible, the self enrolment is visible and if the user has the
556
    // capability "theme/universe:viewhintcourseselfenrol".
557
    if (
558
        get_config('theme_universe', 'showhintcourseselfenrol') == 1
559
        && $allowtoshowhint == true
560
        && $PAGE->has_set_url()
561
        && $PAGE->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)
562
        && $COURSE->visible == true
563
    ) {
564
 
565
        // Get the active enrol instances for this course.
566
        $enrolinstances = enrol_get_instances($COURSE->id, true);
567
 
568
        // Prepare to remember when self enrolment is / will be possible.
569
        $selfenrolmentpossiblecurrently = false;
570
        $selfenrolmentpossiblefuture = false;
571
        foreach ($enrolinstances as $instance) {
572
            // Check if unrestricted self enrolment is possible currently or in the future.
573
            $now = (new \DateTime("now", \core_date::get_server_timezone_object()))->getTimestamp();
574
            if (
575
                $instance->enrol == 'self' && empty($instance->password) && $instance->customint6 == 1 &&
576
                (empty($instance->enrolenddate) || $instance->enrolenddate > $now)
577
            ) {
578
 
579
                // Build enrol instance object with all necessary information for rendering the note later.
580
                $instanceobject = new stdClass();
581
 
582
                // Remember instance name.
583
                if (empty($instance->name)) {
584
                    $instanceobject->name = get_string('pluginname', 'enrol_self') .
585
                        " (" . get_string('defaultcoursestudent', 'core') . ")";
586
                } else {
587
                    $instanceobject->name = $instance->name;
588
                }
589
 
590
                // Remember type of unrestrictedness.
591
                if (empty($instance->enrolenddate) && empty($instance->enrolstartdate)) {
592
                    $instanceobject->unrestrictedness = 'unlimited';
593
                    $selfenrolmentpossiblecurrently = true;
594
                } else if (
595
                    empty($instance->enrolstartdate) &&
596
                    !empty($instance->enrolenddate) && $instance->enrolenddate > $now
597
                ) {
598
                    $instanceobject->unrestrictedness = 'until';
599
                    $selfenrolmentpossiblecurrently = true;
600
                } else if (
601
                    empty($instance->enrolenddate) &&
602
                    !empty($instance->enrolstartdate) && $instance->enrolstartdate > $now
603
                ) {
604
                    $instanceobject->unrestrictedness = 'from';
605
                    $selfenrolmentpossiblefuture = true;
606
                } else if (
607
                    empty($instance->enrolenddate) &&
608
                    !empty($instance->enrolstartdate) && $instance->enrolstartdate <= $now
609
                ) {
610
                    $instanceobject->unrestrictedness = 'since';
611
                    $selfenrolmentpossiblecurrently = true;
612
                } else if (
613
                    !empty($instance->enrolstartdate) && $instance->enrolstartdate > $now &&
614
                    !empty($instance->enrolenddate) && $instance->enrolenddate > $now
615
                ) {
616
                    $instanceobject->unrestrictedness = 'fromuntil';
617
                    $selfenrolmentpossiblefuture = true;
618
                } else if (
619
                    !empty($instance->enrolstartdate) && $instance->enrolstartdate <= $now &&
620
                    !empty($instance->enrolenddate) && $instance->enrolenddate > $now
621
                ) {
622
                    $instanceobject->unrestrictedness = 'sinceuntil';
623
                    $selfenrolmentpossiblecurrently = true;
624
                } else {
625
                    // This should not happen, thus continue to next instance.
626
                    continue;
627
                }
628
 
629
                // Remember enrol start date.
630
                if (!empty($instance->enrolstartdate)) {
631
                    $instanceobject->startdate = $instance->enrolstartdate;
632
                } else {
633
                    $instanceobject->startdate = null;
634
                }
635
 
636
                // Remember enrol end date.
637
                if (!empty($instance->enrolenddate)) {
638
                    $instanceobject->enddate = $instance->enrolenddate;
639
                } else {
640
                    $instanceobject->enddate = null;
641
                }
642
 
643
                // Remember this instance.
644
                $selfenrolinstances[$instance->id] = $instanceobject;
645
            }
646
        }
647
 
648
        // If there is at least one unrestricted enrolment instance,
649
        // show the hint with information about each unrestricted active self enrolment in the course.
650
        if (
651
            !empty($selfenrolinstances) &&
652
            ($selfenrolmentpossiblecurrently == true || $selfenrolmentpossiblefuture == true)
653
        ) {
654
 
655
            // Prepare template context.
656
            $templatecontext = array();
657
 
658
            // Add the start of the hint t the template context
659
            // depending on the fact if enrolment is already possible currently or will be in the future.
660
            if ($selfenrolmentpossiblecurrently == true) {
661
                $templatecontext['selfenrolhintstart'] = get_string('showhintcourseselfenrolstartcurrently', 'theme_universe');
662
            } else if ($selfenrolmentpossiblefuture == true) {
663
                $templatecontext['selfenrolhintstart'] = get_string('showhintcourseselfenrolstartfuture', 'theme_universe');
664
            }
665
 
666
            // Iterate over all enrolment instances to output the details.
667
            foreach ($selfenrolinstances as $selfenrolinstanceid => $selfenrolinstanceobject) {
668
                // If the user has the capability to config self enrolments, enrich the instance name with the settings link.
669
                if (has_capability('enrol/self:config', \context_course::instance($COURSE->id))) {
670
                    $url = new moodle_url('/enrol/editinstance.php', array(
671
                        'courseid' => $COURSE->id,
126 ariadna 672
                        'id' => $selfenrolinstanceid,
673
                        'type' => 'self'
1 efrain 674
                    ));
675
                    $selfenrolinstanceobject->name = html_writer::link($url, $selfenrolinstanceobject->name);
676
                }
677
 
678
                // Add the enrolment instance information to the template context depending on the instance configuration.
679
                if ($selfenrolinstanceobject->unrestrictedness == 'unlimited') {
680
                    $templatecontext['selfenrolinstances'][] = get_string(
681
                        'showhintcourseselfenrolunlimited',
682
                        'theme_universe',
683
                        array('name' => $selfenrolinstanceobject->name)
684
                    );
685
                } else if ($selfenrolinstanceobject->unrestrictedness == 'until') {
686
                    $templatecontext['selfenrolinstances'][] = get_string(
687
                        'showhintcourseselfenroluntil',
688
                        'theme_universe',
689
                        array(
690
                            'name' => $selfenrolinstanceobject->name,
691
                            'until' => userdate($selfenrolinstanceobject->enddate)
692
                        )
693
                    );
694
                } else if ($selfenrolinstanceobject->unrestrictedness == 'from') {
695
                    $templatecontext['selfenrolinstances'][] = get_string(
696
                        'showhintcourseselfenrolfrom',
697
                        'theme_universe',
698
                        array(
699
                            'name' => $selfenrolinstanceobject->name,
700
                            'from' => userdate($selfenrolinstanceobject->startdate)
701
                        )
702
                    );
703
                } else if ($selfenrolinstanceobject->unrestrictedness == 'since') {
704
                    $templatecontext['selfenrolinstances'][] = get_string(
705
                        'showhintcourseselfenrolsince',
706
                        'theme_universe',
707
                        array(
708
                            'name' => $selfenrolinstanceobject->name,
709
                            'since' => userdate($selfenrolinstanceobject->startdate)
710
                        )
711
                    );
712
                } else if ($selfenrolinstanceobject->unrestrictedness == 'fromuntil') {
713
                    $templatecontext['selfenrolinstances'][] = get_string(
714
                        'showhintcourseselfenrolfromuntil',
715
                        'theme_universe',
716
                        array(
717
                            'name' => $selfenrolinstanceobject->name,
718
                            'until' => userdate($selfenrolinstanceobject->enddate),
719
                            'from' => userdate($selfenrolinstanceobject->startdate)
720
                        )
721
                    );
722
                } else if ($selfenrolinstanceobject->unrestrictedness == 'sinceuntil') {
723
                    $templatecontext['selfenrolinstances'][] = get_string(
724
                        'showhintcourseselfenrolsinceuntil',
725
                        'theme_universe',
726
                        array(
727
                            'name' => $selfenrolinstanceobject->name,
728
                            'until' => userdate($selfenrolinstanceobject->enddate),
729
                            'since' => userdate($selfenrolinstanceobject->startdate)
730
                        )
731
                    );
732
                }
733
            }
734
 
735
            // If the user has the capability to config self enrolments, add the call for action to the template context.
736
            if (has_capability('enrol/self:config', \context_course::instance($COURSE->id))) {
737
                $templatecontext['calltoaction'] = true;
738
            } else {
739
                $templatecontext['calltoaction'] = false;
740
            }
741
 
742
            // Render template and add it to HTML code.
743
            $html .= $OUTPUT->render_from_template('theme_universe/course-hint-selfenrol', $templatecontext);
744
        }
745
    }
746
 
747
    // If the setting showswitchedroleincourse is set and the user has switched his role,
748
    // a hint for the role switch will be shown.
749
    if (
750
        get_config('theme_universe', 'showswitchedroleincourse') == 1
751
        && is_role_switched($COURSE->id)
752
    ) {
753
 
754
        // Get the role name switched to.
755
        $opts = \user_get_user_navigation_info($USER, $PAGE);
756
        $role = $opts->metadata['rolename'];
757
 
758
        // Get the URL to switch back (normal role).
759
        $url = new moodle_url(
760
            '/course/switchrole.php',
761
            array(
762
                'id' => $COURSE->id,
763
                'sesskey' => sesskey(),
764
                'switchrole' => 0,
765
                'returnurl' => $PAGE->url->out_as_local_url(false)
766
            )
767
        );
768
 
769
        // Prepare template context.
770
        $templatecontext = array(
771
            'role' => $role,
772
            'url' => $url->out()
773
        );
774
 
775
        // Render template and add it to HTML code.
776
        $html .= $OUTPUT->render_from_template('theme_universe/course-hint-switchedrole', $templatecontext);
777
    }
778
 
779
    // Return HTML code.
780
    return $html;
781
}
782
 
783
/**
784
 * Serves the H5P Custom CSS.
785
 *
786
 * @param string $filename The filename.
787
 * @param theme_config $theme The theme config object.
788
 *
789
 * @throws dml_exception
790
 */
126 ariadna 791
function theme_universe_serve_hvp_css($filename, $theme)
792
{
1 efrain 793
    global $CFG, $PAGE;
794
 
795
    require_once($CFG->dirroot . '/lib/configonlylib.php'); // For min_enable_zlib_compression.
796
 
797
    $PAGE->set_context(context_system::instance());
798
    $themename = $theme->name;
799
 
800
    $settings = new \theme_universe\util\theme_settings();
801
    $content = $settings->hvpcss;
802
 
803
    $md5content = md5($content);
804
    $md5stored = get_config('theme_universe', 'hvpccssmd5');
805
    if ((empty($md5stored)) || ($md5stored != $md5content)) {
806
        // Content changed, so the last modified time needs to change.
807
        set_config('hvpccssmd5', $md5content, $themename);
808
        $lastmodified = time();
809
        set_config('hvpccsslm', $lastmodified, $themename);
810
    } else {
811
        $lastmodified = get_config($themename, 'hvpccsslm');
812
        if (empty($lastmodified)) {
813
            $lastmodified = time();
814
        }
815
    }
816
 
817
    // Sixty days only - the revision may get incremented quite often.
818
    $lifetime = 60 * 60 * 24 * 60;
819
 
820
    header('HTTP/1.1 200 OK');
821
 
822
    header('Etag: "' . $md5content . '"');
823
    header('Content-Disposition: inline; filename="' . $filename . '"');
824
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastmodified) . ' GMT');
825
    header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT');
826
    header('Pragma: ');
827
    header('Cache-Control: public, max-age=' . $lifetime);
828
    header('Accept-Ranges: none');
829
    header('Content-Type: text/css; charset=utf-8');
830
    if (!min_enable_zlib_compression()) {
831
        header('Content-Length: ' . strlen($content));
832
    }
833
 
834
    echo $content;
835
 
836
    die;
837
}
838
 
839
/**
840
 * Return the files from the additionalresources file area as templatecontext structure.
841
 * It was designed to compose the files for the settings-additionalresources-filelist.mustache template.
842
 * This function always loads the files from the filearea which is not really performant.
843
 * Thus, you have to take care where and how often you use it (or add some caching).
844
 *
845
 * @return array|null
846
 * @throws coding_exception
847
 * @throws dml_exception
848
 */
126 ariadna 849
function theme_universe_get_additionalresources_templatecontext()
850
{
1 efrain 851
    global $OUTPUT;
852
 
853
    // Static variable to remember the files for subsequent calls of this function.
854
    static $filesforcontext = null;
855
 
856
    if ($filesforcontext == null) {
857
        // Get the system context.
858
        $systemcontext = \context_system::instance();
859
 
860
        // Get filearea.
861
        $fs = get_file_storage();
862
 
863
        // Get all files from filearea.
864
        $files = $fs->get_area_files($systemcontext->id, 'theme_universe', 'additionalresources', false, 'itemid', false);
865
 
866
        // Iterate over the files and fill the templatecontext of the file list.
867
        $filesforcontext = [];
868
        foreach ($files as $af) {
126 ariadna 869
            $urlpersistent = new moodle_url('/pluginfile.php/1/theme_universe/additionalresources/0/' . $af->get_filename());
870
            $urlrevisioned = new moodle_url('/pluginfile.php/1/theme_universe/additionalresources/' . theme_get_revision() .
871
                '/' . $af->get_filename());
872
            $filesforcontext[] = [
873
                'filename' => $af->get_filename(),
874
                'filetype' => $af->get_mimetype(),
875
                'filesize' => display_size($af->get_filesize()),
876
                'fileicon' => $OUTPUT->image_icon(file_file_icon($af), get_mimetype_description($af)),
877
                'fileurlpersistent' => $urlpersistent->out(),
878
                'fileurlrevisioned' => $urlrevisioned->out(),
879
            ];
1 efrain 880
        }
881
    }
882
 
883
    return $filesforcontext;
884
}
885
 
886
/**
887
 * Return the files from the customfonts file area as templatecontext structure.
888
 * It was designed to compose the files for the settings-customfonts-filelist.mustache template.
889
 * This function always loads the files from the filearea which is not really performant.
890
 * Thus, you have to take care where and how often you use it (or add some caching).
891
 *
892
 * @return array|null
893
 * @throws coding_exception
894
 * @throws dml_exception
895
 * Credits: Boost_Union
896
 */
126 ariadna 897
function theme_universe_get_customfonts_templatecontext()
898
{
1 efrain 899
    global $OUTPUT;
900
 
901
    // Static variable to remember the files for subsequent calls of this function.
902
    static $filesforcontext = null;
903
 
904
    if ($filesforcontext == null) {
905
        // Get the system context.
906
        $systemcontext = \context_system::instance();
907
 
908
        // Get filearea.
909
        $fs = get_file_storage();
910
 
911
        // Get all files from filearea.
912
        $files = $fs->get_area_files($systemcontext->id, 'theme_universe', 'fontfiles', false, 'itemid', false);
913
 
914
        // Get the webfonts extensions list.
915
        $webfonts = theme_universe_get_webfonts_extensions();
916
 
917
        // Iterate over the files.
918
        $filesforcontext = [];
919
        foreach ($files as $af) {
920
            // Get the filename.
921
            $filename = $af->get_filename();
922
 
923
            // Check if the file is really a font file (as we can't really rely on the upload restriction in settings.php)
924
            // according to its file suffix (as the filetype might not have a known mimetype).
925
            // If it isn't a font file, skip it.
926
            $filenamesuffix = pathinfo($filename, PATHINFO_EXTENSION);
126 ariadna 927
            if (!in_array('.' . $filenamesuffix, $webfonts)) {
1 efrain 928
                continue;
929
            }
930
 
931
            // Otherwise, fill the templatecontext of the file list.
126 ariadna 932
            $urlpersistent = new moodle_url('/pluginfile.php/1/theme_universe/fontfiles/0/' . $filename);
933
            $filesforcontext[] = [
934
                'filename' => $filename,
935
                'fileurlpersistent' => $urlpersistent->out(),
936
            ];
1 efrain 937
        }
938
    }
939
 
940
    return $filesforcontext;
941
}
942
 
943
/**
944
 * Helper function which returns an array of accepted webfonts extensions (including the dots).
945
 *
946
 * @return array
947
 * Credits: Boost_Union
948
 */
126 ariadna 949
function theme_universe_get_webfonts_extensions()
950
{
1 efrain 951
    return ['.eot', '.otf', '.svg', '.ttf', '.woff', '.woff2'];
952
}
953
 
954
/**
955
 * Helper function which makes sure that all webfont file types are registered in the system.
956
 * The webfont file types need to be registered in the system, otherwise the admin settings filepicker wouldn't allow restricting
957
 * the uploadable file types to webfonts only.
958
 *
959
 * Please note: If custom filetypes are defined in config.php, registering additional filetypes is not possible
960
 * due to a restriction in the set_custom_types() function in Moodle core. In this case, this function does not
961
 * register anything and will return false.
962
 *
963
 * @return boolean true if the filetypes were registered, false if not.
964
 * @throws coding_exception
965
 * Credits: Boost_Union
966
 */
126 ariadna 967
function theme_universe_register_webfonts_filetypes()
968
{
1 efrain 969
    global $CFG;
970
 
971
    // If customfiletypes are set in config.php or PHP tests are running, we can't do anything.
972
    if (array_key_exists('customfiletypes', $CFG->config_php_settings) || PHPUNIT_TEST) {
973
        return false;
974
    }
975
 
976
    // Our array of webfont file types to register.
977
    // As we want to keep things simple, we do not set a particular icon for these file types.
978
    // Likewise, we do not set any type groups or use descriptions from the language pack.
979
    $webfonts = [
126 ariadna 980
        'eot' => [
981
            'extension' => 'eot',
982
            'mimetype' => 'application/vnd.ms-fontobject',
983
            'coreicon' => 'unknown',
984
        ],
985
        'otf' => [
986
            'extension' => 'otf',
987
            'mimetype' => 'font/otf',
988
            'coreicon' => 'unknown',
989
        ],
990
        'svg' => [
991
            'extension' => 'svg',
992
            'mimetype' => 'image/svg+xml',
993
            'coreicon' => 'unknown',
994
        ],
995
        'ttf' => [
996
            'extension' => 'ttf',
997
            'mimetype' => 'font/ttf',
998
            'coreicon' => 'unknown',
999
        ],
1000
        'woff' => [
1001
            'extension' => 'woff',
1002
            'mimetype' => 'font/woff',
1003
            'coreicon' => 'unknown',
1004
        ],
1005
        'woff2' => [
1006
            'extension' => 'woff2',
1007
            'mimetype' => 'font/woff2',
1008
            'coreicon' => 'unknown',
1009
        ],
1 efrain 1010
    ];
1011
 
1012
    // First, get the list of currently registered file types.
1013
    $currenttypes = core_filetypes::get_types();
1014
 
1015
    // Iterate over the webfonts file types.
1016
    foreach ($webfonts as $f) {
1017
        // If the file type is already registered, skip it.
1018
        if (array_key_exists($f['extension'], $currenttypes)) {
1019
            continue;
1020
        }
1021
 
1022
        // Otherwise, register the file type.
1023
        core_filetypes::add_type($f['extension'], $f['mimetype'], $f['coreicon']);
1024
    }
1025
 
1026
    return true;
1027
}