Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

main/admin/course_list_admin.php (1 issue)

Severity
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
/**
6
 * This script shows a list of courses and allows searching for courses codes
7
 * and names.
8
 */
9
$cidReset = true;
10
require_once __DIR__.'/../inc/global.inc.php';
11
$this_section = SECTION_PLATFORM_ADMIN;
12
api_protect_admin_script();
13
$sessionId = isset($_GET['session_id']) ? $_GET['session_id'] : null;
14
$addTeacherColumn = true;
15
16
/**
17
 * Get the number of courses which will be displayed.
18
 *
19
 * @throws Exception
20
 *
21
 * @return int The number of matching courses
22
 */
23
function get_number_of_courses()
24
{
25
    return get_course_data(0, 0, 0, 0, null, true);
26
}
27
28
/**
29
 * Get course data to display.
30
 *
31
 * @param int    $from
32
 * @param int    $number_of_items
33
 * @param int    $column
34
 * @param string $direction
35
 *
36
 * @throws Exception
37
 *
38
 * @return array
39
 */
40
function get_course_data($from, $number_of_items, $column, $direction, $dataFunctions = [], $getCount = false)
41
{
42
    $addTeacherColumn = true;
43
    $table = Database::get_main_table(TABLE_MAIN_COURSE);
44
45
    $from = (int) $from;
46
    $number_of_items = (int) $number_of_items;
47
    $column = (int) $column;
48
49
    if (!in_array(strtolower($direction), ['asc', 'desc'])) {
50
        $direction = 'desc';
51
    }
52
53
    $teachers = '';
54
    if ($addTeacherColumn) {
55
        $teachers = " GROUP_CONCAT(cu.user_id SEPARATOR ',') as col4, ";
56
    }
57
    $select = "SELECT
58
                code AS col0,
59
                title AS col1,
60
                creation_date AS col2,
61
                $teachers
62
                visibility,
63
                directory,
64
                visual_code,
65
                course.code,
66
                course.id ";
67
68
    if ($getCount) {
69
        $select = 'SELECT COUNT(DISTINCT(course.id)) as count ';
70
    }
71
72
    $sql = "$select FROM $table course";
73
    if (api_is_multiple_url_enabled()) {
74
        $access_url_rel_course_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
75
        $sql .= " INNER JOIN $access_url_rel_course_table url_rel_course
76
                  ON (course.id = url_rel_course.c_id)";
77
    }
78
79
    $tableCourseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
80
    $sql .= "
81
            LEFT JOIN $tableCourseRelUser cu
82
            ON (course.id = cu.c_id AND cu.status = ".COURSEMANAGER." )
83
        ";
84
85
    $sql .= ' WHERE 1=1 ';
86
    if (isset($_GET['keyword'])) {
87
        $keyword = Database::escape_string("%".trim($_GET['keyword'])."%");
88
        $sql .= " AND  (
89
            title LIKE '".$keyword."' OR
90
            code LIKE '".$keyword."' OR
91
            visual_code LIKE '".$keyword."'
92
        )
93
        ";
94
    } elseif (isset($_GET['keyword_code'])) {
95
        $keyword_code = Database::escape_string("%".$_GET['keyword_code']."%");
96
        $keyword_title = Database::escape_string("%".$_GET['keyword_title']."%");
97
        $keyword_category = isset($_GET['keyword_category'])
98
            ? Database::escape_string("%".$_GET['keyword_category']."%")
99
            : null;
100
        $keyword_language = Database::escape_string("%".$_GET['keyword_language']."%");
101
        $keyword_visibility = Database::escape_string("%".$_GET['keyword_visibility']."%");
102
        $keyword_subscribe = Database::escape_string($_GET['keyword_subscribe']);
103
        $keyword_unsubscribe = Database::escape_string($_GET['keyword_unsubscribe']);
104
105
        $sql .= " AND
106
                title LIKE '".$keyword_title."' AND
107
                (code LIKE '".$keyword_code."' OR visual_code LIKE '".$keyword_code."') AND
108
                course_language LIKE '".$keyword_language."' AND
109
                visibility LIKE '".$keyword_visibility."' AND
110
                subscribe LIKE '".$keyword_subscribe."' AND
111
                unsubscribe LIKE '".$keyword_unsubscribe."'";
112
113
        if (!empty($keyword_category)) {
114
            $sql .= " AND category_code LIKE '".$keyword_category."' ";
115
        }
116
    }
117
118
    // Adding the filter to see the user's only of the current access_url.
119
    if (api_is_multiple_url_enabled()) {
120
        $sql .= " AND url_rel_course.access_url_id = ".api_get_current_access_url_id();
121
    }
122
123
    if ($addTeacherColumn) {
124
        $teachers = isset($_GET['course_teachers']) ? $_GET['course_teachers'] : [];
125
        if (!empty($teachers)) {
126
            $teachers = array_map('intval', $teachers);
127
            $addNull = '';
128
            foreach ($teachers as $key => $teacherId) {
129
                if (0 === $teacherId) {
130
                    $addNull = 'OR cu.user_id IS NULL ';
131
                    unset($key);
132
                }
133
            }
134
            $sql .= ' AND ( cu.user_id IN ("'.implode('", "', $teachers).'") '.$addNull.' ) ';
135
        }
136
137
        if (false === $getCount) {
138
            $sql .= " GROUP BY course.id ";
139
        }
140
    }
141
142
    if ($getCount) {
143
        $res = Database::query($sql);
144
        $row = Database::fetch_array($res);
145
        if ($row) {
146
            return (int) $row['count'];
147
        }
148
149
        return 0;
150
    }
151
    $sql .= " ORDER BY col$column $direction ";
152
    $sql .= " LIMIT $from, $number_of_items";
153
154
    $res = Database::query($sql);
155
    $courses = [];
156
    $path = api_get_path(WEB_CODE_PATH);
157
    $coursePath = api_get_path(WEB_COURSE_PATH);
158
159
    $icon = Display::return_icon('teacher.png', get_lang('Teacher'), [], ICON_SIZE_TINY);
160
161
    while ($course = Database::fetch_array($res)) {
162
        $courseId = $course['id'];
163
        $courseCode = $course['code'];
164
165
        // Place colour icons in front of courses.
166
        $showVisualCode = $course['visual_code'] != $courseCode ? Display::label($course['visual_code'], 'info') : null;
167
        $course[1] = get_course_visibility_icon($course['visibility']).PHP_EOL
168
            .Display::url(Security::remove_XSS($course[1]), $coursePath.$course['directory'].'/index.php').PHP_EOL
169
            .$showVisualCode;
170
        $course[5] = $course[5] == SUBSCRIBE_ALLOWED ? get_lang('Yes') : get_lang('No');
171
        $course[6] = $course[6] == UNSUBSCRIBE_ALLOWED ? get_lang('Yes') : get_lang('No');
172
173
        $actions = [];
174
        $actions[] = Display::url(
175
            Display::return_icon('info2.png', get_lang('Info')),
176
            "course_information.php?code=$courseCode"
177
        );
178
        /*$actions[] = Display::url(
179
            Display::return_icon('course_home.png', get_lang('CourseHomepage')),
180
            $coursePath.$course['directory'].'/index.php'
181
        );*/
182
        $actions[] = Display::url(
183
            Display::return_icon('statistics.png', get_lang('Tracking')),
184
            $path.'tracking/courseLog.php?'.api_get_cidreq_params($courseCode)
185
        );
186
        $actions[] = Display::url(
187
            Display::return_icon('edit.png', get_lang('Edit')),
188
            $path.'admin/course_edit.php?id='.$courseId
189
        );
190
        $actions[] = Display::url(
191
            Display::return_icon('backup.png', get_lang('CreateBackup')),
192
            $path.'coursecopy/create_backup.php?'.api_get_cidreq_params($courseCode)
193
        );
194
        $actions[] = Display::url(
195
            Display::return_icon('delete.png', get_lang('Delete')),
196
            $path.'admin/course_list_admin.php?delete_course='.$courseCode,
197
            [
198
                'onclick' => "javascript: if (!confirm('"
199
                    .addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."')) return false;",
200
            ]
201
        );
202
203
        $course['creation_date'] = api_get_local_time($course['col2']);
204
        $lastAccessLocalTime = '';
205
        $lastAccess = Tracking::getLastConnectionDateByCourse($courseId);
206
        if ($lastAccess) {
207
            $lastAccessLocalTime = api_get_local_time($lastAccess);
208
        }
209
210
        $courseItem = [
211
            $course[0],
212
            $course[1],
213
            $course['creation_date'],
214
            $lastAccessLocalTime,
215
        ];
216
217
        if ($addTeacherColumn) {
218
            $teacherIdList = array_filter(explode(',', $course['col4']));
219
            $teacherList = [];
220
            if (!empty($teacherIdList)) {
221
                foreach ($teacherIdList as $teacherId) {
222
                    $userInfo = api_get_user_info($teacherId);
223
                    if ($userInfo) {
224
                        $teacherList[] = $userInfo['complete_name'];
225
                    }
226
                }
227
            }
228
            $courseItem[] = '<ul class="list-inline"><li>'
229
                ."$icon ".implode("</li><li>$icon ", $teacherList)
230
                .'</li></ul>';
231
        }
232
        $courseItem[] = implode(PHP_EOL, $actions);
233
        $courses[] = $courseItem;
234
    }
235
236
    return $courses;
237
}
238
239
/**
240
 * Return an icon representing the visibility of the course.
241
 *
242
 * @param string $visibility
243
 *
244
 * @return string
245
 */
246
function get_course_visibility_icon($visibility)
247
{
248
    $style = 'margin-bottom:0;margin-right:5px;';
249
    switch ($visibility) {
250
        case 0:
251
            return Display::return_icon(
252
                'bullet_red.png',
253
                get_lang('CourseVisibilityClosed'),
254
                ['style' => $style]
255
            );
256
            break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
257
        case 1:
258
            return Display::return_icon(
259
                'bullet_orange.png',
260
                get_lang('Private'),
261
                ['style' => $style]
262
            );
263
            break;
264
        case 2:
265
            return Display::return_icon(
266
                'bullet_green.png',
267
                get_lang('OpenToThePlatform'),
268
                ['style' => $style]
269
            );
270
            break;
271
        case 3:
272
            return Display::return_icon(
273
                'bullet_blue.png',
274
                get_lang('OpenToTheWorld'),
275
                ['style' => $style]
276
            );
277
            break;
278
        case 4:
279
            return Display::return_icon(
280
                'bullet_grey.png',
281
                get_lang('CourseVisibilityHidden'),
282
                ['style' => $style]
283
            );
284
            break;
285
        default:
286
            return '';
287
    }
288
}
289
290
if (isset($_POST['action'])) {
291
    switch ($_POST['action']) {
292
        // Delete selected courses
293
        case 'delete_courses':
294
            if (!empty($_POST['course'])) {
295
                $course_codes = $_POST['course'];
296
                if (count($course_codes) > 0) {
297
                    foreach ($course_codes as $course_code) {
298
                        CourseManager::delete_course($course_code);
299
                    }
300
                }
301
302
                Display::addFlash(Display::return_message(get_lang('Deleted')));
303
            }
304
            break;
305
    }
306
}
307
$content = '';
308
$message = '';
309
$actions = '';
310
311
if (isset($_GET['search']) && $_GET['search'] === 'advanced') {
312
    // Get all course categories
313
    $interbreadcrumb[] = [
314
        'url' => 'index.php',
315
        'name' => get_lang('PlatformAdmin'),
316
    ];
317
    $interbreadcrumb[] = [
318
        'url' => 'course_list_admin.php',
319
        'name' => get_lang('CourseList'),
320
    ];
321
    $tool_name = get_lang('SearchACourse');
322
    $form = new FormValidator('advanced_course_search', 'get');
323
    $form->addElement('header', $tool_name);
324
    $form->addText('keyword_code', get_lang('CourseCode'), false);
325
    $form->addText('keyword_title', get_lang('Title'), false);
326
327
    // Category code
328
    $url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=search_category';
329
330
    $form->addElement(
331
        'select_ajax',
332
        'keyword_category',
333
        get_lang('CourseFaculty'),
334
        null,
335
        [
336
            'url' => $url,
337
        ]
338
    );
339
340
    $el = $form->addSelectLanguage('keyword_language', get_lang('CourseLanguage'));
341
    $el->addOption(get_lang('All'), '%');
342
343
    if ($addTeacherColumn) {
344
        $form->addSelectAjax(
345
            'course_teachers',
346
            get_lang('CourseTeachers'),
347
            [0 => get_lang('None')],
348
            [
349
                'url' => api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=teacher_to_basis_course',
350
                'id' => 'course_teachers',
351
                'multiple' => 'multiple',
352
            ]
353
        );
354
        $form->addLabel('', '<button id="set_none_teacher" class="btn ">'.get_lang('None').'</button>');
355
    }
356
357
    $form->addElement('radio', 'keyword_visibility', get_lang('CourseAccess'), get_lang('OpenToTheWorld'), COURSE_VISIBILITY_OPEN_WORLD);
358
    $form->addElement('radio', 'keyword_visibility', null, get_lang('OpenToThePlatform'), COURSE_VISIBILITY_OPEN_PLATFORM);
359
    $form->addElement('radio', 'keyword_visibility', null, get_lang('Private'), COURSE_VISIBILITY_REGISTERED);
360
    $form->addElement('radio', 'keyword_visibility', null, get_lang('CourseVisibilityClosed'), COURSE_VISIBILITY_CLOSED);
361
    $form->addElement('radio', 'keyword_visibility', null, get_lang('CourseVisibilityHidden'), COURSE_VISIBILITY_HIDDEN);
362
    $form->addElement('radio', 'keyword_visibility', null, get_lang('All'), '%');
363
    $form->addElement('radio', 'keyword_subscribe', get_lang('Subscription'), get_lang('Allowed'), 1);
364
    $form->addElement('radio', 'keyword_subscribe', null, get_lang('Denied'), 0);
365
    $form->addElement('radio', 'keyword_subscribe', null, get_lang('All'), '%');
366
    $form->addElement('radio', 'keyword_unsubscribe', get_lang('Unsubscription'), get_lang('AllowedToUnsubscribe'), 1);
367
    $form->addElement('radio', 'keyword_unsubscribe', null, get_lang('NotAllowedToUnsubscribe'), 0);
368
    $form->addElement('radio', 'keyword_unsubscribe', null, get_lang('All'), '%');
369
    $form->addButtonSearch(get_lang('SearchCourse'));
370
    $defaults['keyword_language'] = '%';
371
    $defaults['keyword_visibility'] = '%';
372
    $defaults['keyword_subscribe'] = '%';
373
    $defaults['keyword_unsubscribe'] = '%';
374
    $form->setDefaults($defaults);
375
    $content .= $form->returnForm();
376
} else {
377
    $interbreadcrumb[] = [
378
        'url' => 'index.php',
379
        'name' => get_lang('PlatformAdmin'),
380
    ];
381
    $tool_name = get_lang('CourseList');
382
    if (isset($_GET['delete_course'])) {
383
        $result = CourseManager::delete_course($_GET['delete_course']);
384
        if ($result) {
385
            Display::addFlash(Display::return_message(get_lang('Deleted')));
386
        }
387
    }
388
    // Create a search-box
389
    $form = new FormValidator(
390
        'search_simple',
391
        'get',
392
        '',
393
        '',
394
        [],
395
        FormValidator::LAYOUT_INLINE
396
    );
397
    $form->addElement(
398
        'text',
399
        'keyword',
400
        null,
401
        ['id' => 'course-search-keyword', 'aria-label' => get_lang('SearchCourse')]
402
    );
403
    $form->addButtonSearch(get_lang('SearchCourse'));
404
    $advanced = '<a class="btn btn-default" href="'.api_get_path(WEB_CODE_PATH).'admin/course_list_admin.php?search=advanced">
405
        <em class="fa fa-search"></em> '.
406
        get_lang('AdvancedSearch').'</a>';
407
408
    // Create a filter by session
409
    $sessionFilter = new FormValidator(
410
        'course_filter',
411
        'get',
412
        '',
413
        '',
414
        [],
415
        FormValidator::LAYOUT_INLINE
416
    );
417
418
    $courseListUrl = api_get_self();
419
    $actions1 = Display::url(
420
        Display::return_icon(
421
            'new_course.png',
422
            get_lang('AddCourse'),
423
            [],
424
            ICON_SIZE_MEDIUM
425
        ),
426
        api_get_path(WEB_CODE_PATH).'admin/course_add.php'
427
    );
428
429
    if (api_get_setting('course_validation') === 'true') {
430
        $actions1 .= Display::url(
431
            Display::return_icon(
432
                'course_request_pending.png',
433
                get_lang('ReviewCourseRequests'),
434
                [],
435
                ICON_SIZE_MEDIUM
436
            ),
437
            api_get_path(WEB_CODE_PATH).'admin/course_request_review.php'
438
        );
439
    }
440
441
    $actions2 = $form->returnForm();
442
    //$actions3 = $sessionFilter->returnForm();
443
    $actions4 = $advanced;
444
445
    $actions = Display::toolbarAction(
446
        'toolbar',
447
        [$actions1, $actions2, $actions4],
448
        [2, 4, 3, 3]
449
    );
450
451
    // Create a sortable table with the course data
452
    $table = new SortableTable(
453
        'course_list_admin',
454
        'get_number_of_courses',
455
        'get_course_data',
456
        1,
457
        20,
458
        'ASC',
459
        'course_list_admin'
460
    );
461
462
    $parameters = [];
463
    if (isset($_GET['keyword'])) {
464
        $parameters = ['keyword' => Security::remove_XSS($_GET['keyword'])];
465
    } elseif (isset($_GET['keyword_code'])) {
466
        $parameters['keyword_code'] = Security::remove_XSS($_GET['keyword_code']);
467
        $parameters['keyword_title'] = Security::remove_XSS($_GET['keyword_title']);
468
        if (isset($_GET['keyword_category'])) {
469
            $parameters['keyword_category'] = Security::remove_XSS($_GET['keyword_category']);
470
        }
471
        $parameters['keyword_language'] = Security::remove_XSS($_GET['keyword_language']);
472
        $parameters['keyword_visibility'] = Security::remove_XSS($_GET['keyword_visibility']);
473
        $parameters['keyword_subscribe'] = Security::remove_XSS($_GET['keyword_subscribe']);
474
        $parameters['keyword_unsubscribe'] = Security::remove_XSS($_GET['keyword_unsubscribe']);
475
    }
476
477
    if (isset($_GET['course_teachers'])) {
478
        $parsed = array_map('intval', $_GET['course_teachers']);
479
        $parameters["course_teachers"] = '';
480
        foreach ($parsed as $key => $teacherId) {
481
            $parameters["course_teachers[$key]"] = $teacherId;
482
        }
483
    }
484
485
    $table->set_additional_parameters($parameters);
486
    $column = 0;
487
    $table->set_header($column++, '', false, 'width="8px"');
488
    $table->set_header($column++, get_lang('Title'), true, null, ['class' => 'title']);
489
    $table->set_header($column++, get_lang('CreationDate'), true, 'width="70px"');
490
    $table->set_header($column++, get_lang('LatestLoginInCourse'), false, 'width="70px"');
491
    //$table->set_header($column++, get_lang('Category'));
492
    //$table->set_header($column++, get_lang('SubscriptionAllowed'), true, 'width="60px"');
493
    //$table->set_header($column++, get_lang('UnsubscriptionAllowed'), false, 'width="50px"');
494
    if ($addTeacherColumn) {
495
        $table->set_header($column++, get_lang('Teachers'), true, ['style' => 'width:350px;']);
496
    }
497
    $table->set_header(
498
        $column++,
499
        get_lang('Action'),
500
        false,
501
        null,
502
        ['class' => 'td_actions', 'style' => 'width:145px;']
503
    );
504
    $table->set_form_actions(
505
        ['delete_courses' => get_lang('DeleteCourse')],
506
        'course'
507
    );
508
    $tab = CourseManager::getCourseListTabs('admin');
509
    $content .= $tab.$table->return_table();
510
}
511
512
$htmlHeadXtra[] = '
513
<script>
514
$(function() {
515
    $("#set_none_teacher").on("click", function () {
516
        $("#course_teachers").val("0").trigger("change");
517
518
        return false;
519
    });
520
});
521
</script>';
522
523
$tpl = new Template($tool_name);
524
$tpl->assign('actions', $actions);
525
$tpl->assign('message', $message);
526
$tpl->assign('content', $content);
527
$tpl->display_one_col_template();
528