Proyectos de Subversion Moodle

Rev

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