Issues (2037)

main/admin/user_list_consent.php (1 issue)

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use ChamiloSession as Session;
5
6
/**
7
 * @author Bart Mollet
8
 * @author Julio Montoya <[email protected]> BeezNest 2011
9
 */
10
$cidReset = true;
11
require_once __DIR__.'/../inc/global.inc.php';
12
13
$urlId = api_get_current_access_url_id();
14
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
15
16
api_protect_admin_script();
17
18
$this_section = SECTION_PLATFORM_ADMIN;
19
20
$extraFields = UserManager::createDataPrivacyExtraFields();
21
Session::write('data_privacy_extra_fields', $extraFields);
22
23
/**
24
 * Prepares the shared SQL query for the user table.
25
 * See get_user_data() and get_number_of_users().
26
 *
27
 * @param bool $getCount Whether to count, or get data
28
 *
29
 * @return string SQL query
30
 */
31
function prepare_user_sql_query($getCount)
32
{
33
    $sql = '';
34
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
35
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
36
37
    if ($getCount) {
38
        $sql .= "SELECT COUNT(u.id) AS total_number_of_items FROM $user_table u";
39
    } else {
40
        $sql .= 'SELECT u.id AS col0, u.official_code AS col2, ';
41
        if (api_is_western_name_order()) {
42
            $sql .= 'u.firstname AS col3, u.lastname AS col4, ';
43
        } else {
44
            $sql .= 'u.lastname AS col3, u.firstname AS col4, ';
45
        }
46
47
        $sql .= " u.username AS col5,
48
                    u.email AS col6,
49
                    u.status AS col7,
50
                    u.active AS col8,
51
                    u.id AS col9,
52
                    u.registration_date AS col10,
53
                    u.expiration_date AS exp,
54
                    u.password,
55
                    v.field_id,
56
                    v.updated_at
57
                FROM $user_table u";
58
    }
59
60
    // adding the filter to see the user's only of the current access_url
61
    if ((api_is_platform_admin() || api_is_session_admin()) && api_get_multiple_access_url()) {
62
        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
63
        $sql .= " INNER JOIN $access_url_rel_user_table url_rel_user
64
                  ON (u.id=url_rel_user.user_id)";
65
    }
66
67
    $extraFields = Session::read('data_privacy_extra_fields');
68
    $extraFieldId = $extraFields['delete_legal'];
69
    $extraFieldIdDeleteAccount = $extraFields['delete_account_extra_field'];
70
71
    $extraFieldValue = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
72
    $sql .= " INNER JOIN $extraFieldValue v
73
              ON (
74
                    u.id = v.item_id AND
75
                    (field_id = $extraFieldId OR field_id = $extraFieldIdDeleteAccount) AND
76
                    v.value = 1
77
              ) ";
78
79
    $keywordList = [
80
        'keyword_firstname',
81
        'keyword_lastname',
82
        'keyword_username',
83
        'keyword_email',
84
        'keyword_officialcode',
85
        'keyword_status',
86
        'keyword_active',
87
        'keyword_inactive',
88
        'check_easy_passwords',
89
    ];
90
91
    $keywordListValues = [];
92
    $atLeastOne = false;
93
    foreach ($keywordList as $keyword) {
94
        $keywordListValues[$keyword] = null;
95
        if (isset($_GET[$keyword]) && !empty($_GET[$keyword])) {
96
            $keywordListValues[$keyword] = $_GET[$keyword];
97
            $atLeastOne = true;
98
        }
99
    }
100
101
    if (false == $atLeastOne) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
102
        $keywordListValues = [];
103
    }
104
105
    if (isset($_GET['keyword']) && !empty($_GET['keyword'])) {
106
        $keywordFiltered = Database::escape_string("%".$_GET['keyword']."%");
107
        $sql .= " WHERE (
108
                    u.firstname LIKE '$keywordFiltered' OR
109
                    u.lastname LIKE '$keywordFiltered' OR
110
                    concat(u.firstname, ' ', u.lastname) LIKE '$keywordFiltered' OR
111
                    concat(u.lastname,' ',u.firstname) LIKE '$keywordFiltered' OR
112
                    u.username LIKE '$keywordFiltered' OR
113
                    u.official_code LIKE '$keywordFiltered' OR
114
                    u.email LIKE '$keywordFiltered'
115
                )
116
        ";
117
    } elseif (isset($keywordListValues) && !empty($keywordListValues)) {
118
        $query_admin_table = '';
119
        $keyword_admin = '';
120
121
        if (isset($keywordListValues['keyword_status']) &&
122
            $keywordListValues['keyword_status'] == PLATFORM_ADMIN
123
        ) {
124
            $query_admin_table = " , $admin_table a ";
125
            $keyword_admin = ' AND a.user_id = u.id ';
126
            $keywordListValues['keyword_status'] = '%';
127
        }
128
129
        $keyword_extra_value = '';
130
131
        $sql .= " $query_admin_table
132
            WHERE (
133
                u.firstname LIKE '".Database::escape_string("%".$keywordListValues['keyword_firstname']."%")."' AND
134
                u.lastname LIKE '".Database::escape_string("%".$keywordListValues['keyword_lastname']."%")."' AND
135
                u.username LIKE '".Database::escape_string("%".$keywordListValues['keyword_username']."%")."' AND
136
                u.email LIKE '".Database::escape_string("%".$keywordListValues['keyword_email']."%")."' AND
137
                u.status LIKE '".Database::escape_string($keywordListValues['keyword_status'])."' ";
138
        if (!empty($keywordListValues['keyword_officialcode'])) {
139
            $sql .= " AND u.official_code LIKE '".Database::escape_string("%".$keywordListValues['keyword_officialcode']."%")."' ";
140
        }
141
142
        $sql .= "
143
            $keyword_admin
144
            $keyword_extra_value
145
        ";
146
147
        if (isset($keywordListValues['keyword_active']) &&
148
            !isset($keywordListValues['keyword_inactive'])
149
        ) {
150
            $sql .= " AND u.active = 1";
151
        } elseif (isset($keywordListValues['keyword_inactive']) &&
152
            !isset($keywordListValues['keyword_active'])
153
        ) {
154
            $sql .= " AND u.active = 0";
155
        }
156
        $sql .= " ) ";
157
    }
158
159
    $preventSessionAdminsToManageAllUsers = api_get_setting('prevent_session_admins_to_manage_all_users');
160
    if (api_is_session_admin() && $preventSessionAdminsToManageAllUsers === 'true') {
161
        $sql .= " AND u.creator_id = ".api_get_user_id();
162
    }
163
164
    // adding the filter to see the user's only of the current access_url
165
    if ((api_is_platform_admin() || api_is_session_admin()) &&
166
        api_get_multiple_access_url()
167
    ) {
168
        $sql .= " AND url_rel_user.access_url_id = ".api_get_current_access_url_id();
169
    }
170
171
    return $sql;
172
}
173
174
/**
175
 * Get the total number of users on the platform.
176
 *
177
 * @see SortableTable#get_total_number_of_items()
178
 */
179
function get_number_of_users()
180
{
181
    $sql = prepare_user_sql_query(true);
182
    $res = Database::query($sql);
183
    $obj = Database::fetch_object($res);
184
185
    return $obj->total_number_of_items;
186
}
187
188
/**
189
 * Get the users to display on the current page (fill the sortable-table).
190
 *
191
 * @param   int     offset of first user to recover
192
 * @param   int     Number of users to get
193
 * @param   int     Column to sort on
194
 * @param   string  Order (ASC,DESC)
195
 *
196
 * @return array Users list
197
 *
198
 * @see SortableTable#get_table_data($from)
199
 */
200
function get_user_data($from, $number_of_items, $column, $direction)
201
{
202
    $sql = prepare_user_sql_query(false);
203
    if (!in_array($direction, ['ASC', 'DESC'])) {
204
        $direction = 'ASC';
205
    }
206
    $column = (int) $column;
207
    $from = (int) $from;
208
    $number_of_items = (int) $number_of_items;
209
    $sql .= " ORDER BY col$column $direction ";
210
    $sql .= " LIMIT $from,$number_of_items";
211
212
    $res = Database::query($sql);
213
214
    $users = [];
215
    $t = time();
216
    while ($user = Database::fetch_row($res)) {
217
        $userPicture = UserManager::getUserPicture(
218
            $user[0],
219
            USER_IMAGE_SIZE_SMALL
220
        );
221
        $photo = '<img
222
            src="'.$userPicture.'" width="22" height="22"
223
            alt="'.api_get_person_name($user[2], $user[3]).'"
224
            title="'.api_get_person_name($user[2], $user[3]).'" />';
225
226
        if (1 == $user[7] && !empty($user[10])) {
227
            // check expiration date
228
            $expiration_time = convert_sql_date($user[10]);
229
            // if expiration date is passed, store a special value for active field
230
            if ($expiration_time < $t) {
231
                $user[7] = '-1';
232
            }
233
        }
234
235
        // forget about the expiration date field
236
        $users[] = [
237
            $user[0],
238
            $photo,
239
            $user[1],
240
            $user[2],
241
            $user[3],
242
            $user[4],
243
            $user[5],
244
            $user[6],
245
            $user[7],
246
            api_get_local_time($user[9]),
247
            $user[12],
248
            Display::dateToStringAgoAndLongDate($user[13]),
249
            $user[0],
250
        ];
251
    }
252
253
    return $users;
254
}
255
256
/**
257
 * Returns a mailto-link.
258
 *
259
 * @param string $email An email-address
260
 *
261
 * @return string HTML-code with a mailto-link
262
 */
263
function email_filter($email)
264
{
265
    return Display::encrypted_mailto_link($email, $email);
266
}
267
268
/**
269
 * Returns a mailto-link.
270
 *
271
 * @param string $name   An email-address
272
 * @param array  $params Deprecated
273
 * @param array  $row
274
 *
275
 * @return string HTML-code with a mailto-link
276
 */
277
function user_filter($name, $params, $row)
278
{
279
    return '<a href="'.api_get_path(WEB_PATH).'whoisonline.php?origin=user_list&id='.$row[0].'">'.$name.'</a>';
280
}
281
282
function requestTypeFilter($fieldId, $url_params, $row)
283
{
284
    $extraFields = Session::read('data_privacy_extra_fields');
285
    $extraFieldId = $extraFields['delete_legal'];
286
287
    if ($fieldId == $extraFieldId) {
288
        return get_lang('DeleteLegal');
289
    } else {
290
        return get_lang('DeleteAccount');
291
    }
292
}
293
294
/**
295
 * Build the modify-column of the table.
296
 *
297
 * @param   int     The user id
298
 * @param   string  URL params to add to table links
299
 * @param   array   Row of elements to alter
300
 *
301
 * @throws Exception
302
 *
303
 * @return string Some HTML-code with modify-buttons
304
 */
305
function modify_filter($user_id, $url_params, $row)
306
{
307
    $_admins_list = Session::read('admin_list', []);
308
    $is_admin = in_array($user_id, $_admins_list);
309
    $token = Security::getTokenFromSession();
310
    $result = '';
311
    $result .= '<a href="user_information.php?user_id='.$user_id.'">'.
312
        Display::return_icon('info2.png', get_lang('Info')).'</a>&nbsp;&nbsp;';
313
314
    $result .= Display::url(
315
        Display::return_icon('message_new.png', get_lang('SendMessage')),
316
        api_get_path(WEB_CODE_PATH).'messages/new_message.php?send_to_user='.$user_id
317
    );
318
    $result .= '&nbsp;&nbsp;';
319
    $extraFields = Session::read('data_privacy_extra_fields');
320
    $extraFieldId = $extraFields['delete_legal'];
321
322
    if ($row[10] == $extraFieldId) {
323
        $result .= Display::url(
324
            Display::return_icon('delete_terms.png', get_lang('RemoveTerms')),
325
            api_get_self().'?user_id='.$user_id.'&action=delete_terms&sec_token='.$token
326
        );
327
        $result .= '&nbsp;&nbsp;';
328
    }
329
330
    if ($user_id != api_get_user_id()) {
331
        $result .= ' <a href="'.api_get_self().'?action=anonymize&user_id='.$user_id.'&'.$url_params.'&sec_token='.$token.'"  onclick="javascript:if(!confirm('."'".addslashes(
332
                api_htmlentities(get_lang('ConfirmYourChoice'))
333
            )."'".')) return false;">'.
334
            Display::return_icon(
335
                'anonymous.png',
336
                get_lang('Anonymize'),
337
                [],
338
                ICON_SIZE_SMALL
339
            ).
340
            '</a>';
341
342
        $result .= ' <a href="'.api_get_self().'?action=delete_user&user_id='.$user_id.'&'.$url_params.'&sec_token='.$token.'"  onclick="javascript:if(!confirm('."'".addslashes(
343
            api_htmlentities(get_lang('ConfirmYourChoice'))
344
        )."'".')) return false;">'.
345
        Display::return_icon(
346
            'delete.png',
347
            get_lang('Delete'),
348
            [],
349
            ICON_SIZE_SMALL
350
        ).
351
        '</a>';
352
    }
353
354
    $editProfileUrl = Display::getProfileEditionLink($user_id, true);
355
356
    $result .= '<a href="'.$editProfileUrl.'">'.
357
        Display::return_icon(
358
            'edit.png',
359
            get_lang('Edit'),
360
            [],
361
            ICON_SIZE_SMALL
362
        ).
363
        '</a>&nbsp;';
364
365
    if ($is_admin) {
366
        $result .= Display::return_icon(
367
            'admin_star.png',
368
            get_lang('IsAdministrator'),
369
            ['width' => ICON_SIZE_SMALL, 'heigth' => ICON_SIZE_SMALL]
370
        );
371
    } else {
372
        $result .= Display::return_icon(
373
            'admin_star_na.png',
374
            get_lang('IsNotAdministrator')
375
        );
376
    }
377
378
    return $result;
379
}
380
381
/**
382
 * Build the active-column of the table to lock or unlock a certain user
383
 * lock = the user can no longer use this account.
384
 *
385
 * @author Patrick Cool <[email protected]>, Ghent University
386
 *
387
 * @param int    $active the current state of the account
388
 * @param string $params
389
 * @param array  $row
390
 *
391
 * @return string Some HTML-code with the lock/unlock button
392
 */
393
function active_filter($active, $params, $row)
394
{
395
    $_user = api_get_user_info();
396
397
    if ($active == '1') {
398
        $action = 'Lock';
399
        $image = 'accept';
400
    } elseif ($active == '-1') {
401
        $action = 'edit';
402
        $image = 'warning';
403
    } elseif ($active == '0') {
404
        $action = 'Unlock';
405
        $image = 'error';
406
    }
407
408
    $result = '';
409
410
    if ($action === 'edit') {
411
        $result = Display::return_icon(
412
            $image.'.png',
413
            get_lang('AccountExpired'),
414
            [],
415
            16
416
        );
417
    } elseif ($row['0'] != $_user['user_id']) {
418
        // you cannot lock yourself out otherwise you could disable all the
419
        // accounts including your own => everybody is locked out and nobody
420
        // can change it anymore.
421
        $result = Display::return_icon(
422
            $image.'.png',
423
            get_lang(ucfirst($action)),
424
            ['onclick' => 'active_user(this);', 'id' => 'img_'.$row['0']],
425
            16
426
        );
427
    }
428
429
    return $result;
430
}
431
432
/**
433
 * Instead of displaying the integer of the status, we give a translation for the status.
434
 *
435
 * @param int $status
436
 *
437
 * @return string translation
438
 *
439
 * @version march 2008
440
 *
441
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
442
 */
443
function status_filter($status)
444
{
445
    $statusname = api_get_status_langvars();
446
447
    return $statusname[$status];
448
}
449
450
if (isset($_GET['keyword']) || isset($_GET['keyword_firstname'])) {
451
    $interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('PlatformAdmin')];
452
    $interbreadcrumb[] = ['url' => 'user_list_consent.php', 'name' => get_lang('UserList')];
453
    $tool_name = get_lang('SearchUsers');
454
} else {
455
    $interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('PlatformAdmin')];
456
    $tool_name = get_lang('UserList');
457
}
458
459
$message = '';
460
461
if (!empty($action)) {
462
    $check = Security::check_token('get');
463
    if ($check) {
464
        switch ($action) {
465
            case 'delete_terms':
466
                UserManager::cleanUserRequestsOfRemoval($_GET['user_id']);
467
468
                Display::addFlash(Display::return_message(get_lang('Deleted')));
469
                header('Location: '.api_get_self());
470
                exit;
471
472
                break;
473
            case 'delete_user':
474
                $message = UserManager::deleteUserWithVerification($_GET['user_id']);
475
                Display::addFlash($message);
476
                header('Location: '.api_get_self());
477
                exit;
478
                break;
479
            case 'delete':
480
                if (api_is_platform_admin()) {
481
                    $number_of_selected_users = count($_POST['id']);
482
                    $number_of_affected_users = 0;
483
                    if (is_array($_POST['id'])) {
484
                        foreach ($_POST['id'] as $index => $user_id) {
485
                            if ($user_id != $_user['user_id']) {
486
                                if (UserManager::delete_user($user_id)) {
487
                                    $number_of_affected_users++;
488
                                }
489
                            }
490
                        }
491
                    }
492
                    if ($number_of_selected_users == $number_of_affected_users) {
493
                        $message = Display::return_message(
494
                            get_lang('SelectedUsersDeleted'),
495
                            'confirmation'
496
                        );
497
                    } else {
498
                        $message = Display::return_message(
499
                            get_lang('SomeUsersNotDeleted'),
500
                            'error'
501
                        );
502
                    }
503
                }
504
                break;
505
            case 'anonymize':
506
                $message = UserManager::anonymizeUserWithVerification($_GET['user_id']);
507
                Display::addFlash($message);
508
                header('Location: '.api_get_self());
509
                exit;
510
                break;
511
        }
512
        Security::clear_token();
513
    }
514
}
515
516
// Create a search-box
517
$form = new FormValidator('search_simple', 'get', null, null, null, 'inline');
518
$form->addText(
519
    'keyword',
520
    get_lang('Search'),
521
    false,
522
    [
523
        'aria-label' => get_lang('SearchUsers'),
524
    ]
525
);
526
$form->addButtonSearch(get_lang('Search'));
527
528
$actionsLeft = '';
529
$actionsCenter = '';
530
$actionsRight = '';
531
$actionsLeft .= $form->returnForm();
532
533
if (isset($_GET['keyword'])) {
534
    $parameters = ['keyword' => Security::remove_XSS($_GET['keyword'])];
535
} elseif (isset($_GET['keyword_firstname'])) {
536
    $parameters['keyword_firstname'] = Security::remove_XSS($_GET['keyword_firstname']);
537
    $parameters['keyword_lastname'] = Security::remove_XSS($_GET['keyword_lastname']);
538
    $parameters['keyword_username'] = Security::remove_XSS($_GET['keyword_username']);
539
    $parameters['keyword_email'] = Security::remove_XSS($_GET['keyword_email']);
540
    $parameters['keyword_officialcode'] = Security::remove_XSS($_GET['keyword_officialcode']);
541
    $parameters['keyword_status'] = Security::remove_XSS($_GET['keyword_status']);
542
    $parameters['keyword_active'] = Security::remove_XSS($_GET['keyword_active']);
543
    $parameters['keyword_inactive'] = Security::remove_XSS($_GET['keyword_inactive']);
544
}
545
// Create a sortable table with user-data
546
$parameters['sec_token'] = Security::get_token();
547
548
$_admins_list = array_keys(UserManager::get_all_administrators());
549
Session::write('admin_list', $_admins_list);
550
// Display Advanced search form.
551
$form = new FormValidator(
552
    'advanced_search',
553
    'get',
554
    '',
555
    '',
556
    [],
557
    FormValidator::LAYOUT_HORIZONTAL
558
);
559
560
$form->addElement('html', '<div id="advanced_search_form" style="display:none;">');
561
$form->addElement('header', get_lang('AdvancedSearch'));
562
$form->addText('keyword_firstname', get_lang('FirstName'), false);
563
$form->addText('keyword_lastname', get_lang('LastName'), false);
564
$form->addText('keyword_username', get_lang('LoginName'), false);
565
$form->addText('keyword_email', get_lang('Email'), false);
566
$form->addText('keyword_officialcode', get_lang('OfficialCode'), false);
567
568
$status_options = [];
569
$status_options['%'] = get_lang('All');
570
$status_options[STUDENT] = get_lang('Student');
571
$status_options[COURSEMANAGER] = get_lang('Teacher');
572
$status_options[DRH] = get_lang('Drh');
573
$status_options[SESSIONADMIN] = get_lang('SessionsAdmin');
574
$status_options[PLATFORM_ADMIN] = get_lang('Administrator');
575
576
$form->addElement(
577
    'select',
578
    'keyword_status',
579
    get_lang('Profile'),
580
    $status_options
581
);
582
$form->addButtonSearch(get_lang('SearchUsers'));
583
584
$defaults = [];
585
$defaults['keyword_active'] = 1;
586
$defaults['keyword_inactive'] = 1;
587
$form->setDefaults($defaults);
588
$form->addElement('html', '</div>');
589
590
$form = $form->returnForm();
591
592
$table = new SortableTable(
593
    'users',
594
    'get_number_of_users',
595
    'get_user_data',
596
    (api_is_western_name_order() xor api_sort_by_first_name()) ? 3 : 2
597
);
598
$table->set_additional_parameters($parameters);
599
$table->set_header(0, '', false, 'width="18px"');
600
$table->set_header(1, get_lang('Photo'), false);
601
$table->set_header(2, get_lang('OfficialCode'));
602
603
if (api_is_western_name_order()) {
604
    $table->set_header(3, get_lang('FirstName'));
605
    $table->set_header(4, get_lang('LastName'));
606
} else {
607
    $table->set_header(3, get_lang('LastName'));
608
    $table->set_header(4, get_lang('FirstName'));
609
}
610
$table->set_header(5, get_lang('LoginName'));
611
$table->set_header(6, get_lang('Email'));
612
$table->set_header(7, get_lang('Profile'));
613
$table->set_header(8, get_lang('Active'));
614
$table->set_header(9, get_lang('RegistrationDate'));
615
$table->set_header(10, get_lang('RequestType'));
616
$table->set_header(11, get_lang('RequestDate'));
617
$table->set_header(12, get_lang('Action'), false);
618
619
$table->set_column_filter(3, 'user_filter');
620
$table->set_column_filter(4, 'user_filter');
621
$table->set_column_filter(6, 'email_filter');
622
$table->set_column_filter(7, 'status_filter');
623
$table->set_column_filter(8, 'active_filter');
624
$table->set_column_filter(12, 'modify_filter');
625
$table->set_column_filter(10, 'requestTypeFilter');
626
627
// Only show empty actions bar if delete users has been blocked
628
$actionsList = [];
629
if (api_is_platform_admin() &&
630
    !api_get_configuration_value('deny_delete_users')
631
) {
632
    $actionsList['delete'] = get_lang('DeleteFromPlatform');
633
}
634
635
$table->set_form_actions($actionsList);
636
637
$table_result = $table->return_table();
638
$extra_search_options = '';
639
$toolbarActions = Display::toolbarAction(
640
    'toolbarUser',
641
    [$actionsLeft, $actionsCenter, $actionsRight],
642
    [4, 4, 4]
643
);
644
645
$noticeMessage = sprintf(
646
    get_lang('InformationRightToBeForgottenLinkX'),
647
    '<a href="https://gdpr-info.eu/art-17-gdpr/">https://gdpr-info.eu/art-17-gdpr/</a>'
648
);
649
$notice = Display::return_message($noticeMessage, 'normal', false);
650
651
$tpl = new Template($tool_name);
652
$tpl->assign('actions', $toolbarActions);
653
$tpl->assign('message', $message);
654
$tpl->assign('content', $form.$table_result.$extra_search_options.$notice);
655
$tpl->display_one_col_template();
656