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

main/admin/user_list.php (1 issue)

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use ChamiloSession as Session;
6
7
/**
8
 * @author Bart Mollet
9
 * @author Julio Montoya <[email protected]> BeezNest 2011
10
 */
11
$cidReset = true;
12
require_once __DIR__.'/../inc/global.inc.php';
13
14
api_protect_session_admin_list_users();
15
16
$urlId = api_get_current_access_url_id();
17
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
18
19
// Login as can be used by different roles
20
if (isset($_GET['user_id']) && $action === 'login_as') {
21
    $check = Security::check_token('get');
22
    if ($check && api_can_login_as($_GET['user_id'])) {
23
        $result = UserManager::loginAsUser($_GET['user_id']);
24
        if ($result) {
25
            $userInfo = api_get_user_info();
26
            $userId = $userInfo['id'];
27
            $message = sprintf(
28
                get_lang('AttemptingToLoginAs'),
29
                $userInfo['complete_name_with_username'],
30
                '',
31
                $userId
32
            );
33
34
            $url = api_get_path(WEB_PATH).'user_portal.php';
35
            $goTo = sprintf(get_lang('LoginSuccessfulGoToX'), Display::url($url, $url));
36
            Display::display_header(get_lang('UserList'));
37
            echo Display::return_message($message, 'normal', false);
38
            echo Display::return_message($goTo, 'normal', false);
39
            Display::display_footer();
40
            exit;
41
        } else {
42
            api_not_allowed(true);
43
        }
44
    }
45
    Security::clear_token();
46
}
47
48
api_protect_admin_script(true);
49
trimVariables();
50
51
$url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=get_user_courses';
52
$urlSession = api_get_path(WEB_AJAX_PATH).'session.ajax.php?a=get_user_sessions';
53
$extraField = new ExtraField('user');
54
$variables = $extraField->get_all_extra_field_by_type(ExtraField::FIELD_TYPE_TAG);
55
$variablesSelect = $extraField->get_all_extra_field_by_type(ExtraField::FIELD_TYPE_SELECT);
56
57
if (!empty($variablesSelect)) {
58
    $variables = array_merge($variables, $variablesSelect);
59
}
60
$variablesToShow = [];
61
if ($variables) {
62
    foreach ($variables as $variableId) {
63
        $extraFieldInfo = $extraField->get($variableId);
64
        $variablesToShow[] = $extraFieldInfo['variable'];
65
    }
66
}
67
68
Session::write('variables_to_show', $variablesToShow);
69
70
$htmlHeadXtra[] = '<script>
71
function load_course_list (div_course,my_user_id) {
72
     $.ajax({
73
        contentType: "application/x-www-form-urlencoded",
74
        beforeSend: function(myObject) {
75
            $("div#"+div_course).html("<img src=\'../inc/lib/javascript/indicator.gif\' />"); },
76
        type: "POST",
77
        url: "'.$url.'",
78
        data: "user_id="+my_user_id,
79
        success: function(datos) {
80
            $("div#"+div_course).html(datos);
81
            $("div#div_"+my_user_id).attr("class","blackboard_show");
82
            $("div#div_"+my_user_id).attr("style","");
83
        }
84
    });
85
}
86
87
function load_session_list(div_session, my_user_id) {
88
     $.ajax({
89
        contentType: "application/x-www-form-urlencoded",
90
        beforeSend: function(myObject) {
91
            $("div#"+div_session).html("<img src=\'../inc/lib/javascript/indicator.gif\' />"); },
92
        type: "POST",
93
        url: "'.$urlSession.'",
94
        data: "user_id="+my_user_id,
95
        success: function(datos) {
96
            $("div#"+div_session).html(datos);
97
            $("div#div_s_"+my_user_id).attr("class","blackboard_show");
98
            $("div#div_s_"+my_user_id).attr("style","");
99
        }
100
    });
101
}
102
103
function active_user(element_div) {
104
    id_image=$(element_div).attr("id");
105
    image_clicked=$(element_div).attr("src");
106
    image_clicked_info = image_clicked.split("/");
107
    image_real_clicked = image_clicked_info[image_clicked_info.length-1];
108
    var status = 1;
109
    if (image_real_clicked == "accept.png") {
110
        status = 0;
111
    }
112
    user_id=id_image.split("_");
113
    ident="#img_"+user_id[1];
114
    if (confirm("'.get_lang('AreYouSureToEditTheUserStatus', '').'")) {
115
         $.ajax({
116
            contentType: "application/x-www-form-urlencoded",
117
            beforeSend: function(myObject) {
118
                $(ident).attr("src","'.Display::returnIconPath('loading1.gif').'"); }, //candy eye stuff
119
            type: "GET",
120
            url: "'.api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=active_user",
121
            data: "user_id="+user_id[1]+"&status="+status,
122
            success: function(data) {
123
                if (data == 1) {
124
                    $(ident).attr("src", "'.Display::returnIconPath('accept.png', ICON_SIZE_TINY).'");
125
                    $(ident).attr("title","'.get_lang('Lock').'");
126
                }
127
                if (data == 0) {
128
                    $(ident).attr("src","'.Display::returnIconPath('error.png').'");
129
                    $(ident).attr("title","'.get_lang('Unlock').'");
130
                }
131
                if (data == -1) {
132
                    $(ident).attr("src", "'.Display::returnIconPath('warning.png').'");
133
                    $(ident).attr("title","'.get_lang('ActionNotAllowed').'");
134
                }
135
            }
136
        });
137
    }
138
}
139
140
function clear_course_list(div_course) {
141
    $("div#"+div_course).html("&nbsp;");
142
    $("div#"+div_course).hide("");
143
}
144
function clear_session_list(div_session) {
145
    $("div#"+div_session).html("&nbsp;");
146
    $("div#"+div_session).hide("");
147
}
148
149
function display_advanced_search_form () {
150
    if ($("#advanced_search_form").css("display") == "none") {
151
        $("#advanced_search_form").css("display","block");
152
        $("#img_plus_and_minus").html(\'&nbsp;'.Display::returnFontAwesomeIcon('arrow-down').' '.get_lang('AdvancedSearch').'\');
153
    } else {
154
        $("#advanced_search_form").css("display","none");
155
        $("#img_plus_and_minus").html(\'&nbsp;'.Display::returnFontAwesomeIcon('arrow-right').' '.get_lang('AdvancedSearch').'\');
156
    }
157
}
158
159
$(function () {
160
    var select_val = $("#input_select_extra_data").val();
161
    if ( document.getElementById(\'extra_data_text\')) {
162
        if (select_val != 0) {
163
            document.getElementById(\'extra_data_text\').style.display="block";
164
            if (document.getElementById(\'input_extra_text\'))
165
                document.getElementById(\'input_extra_text\').value = "";
166
        } else {
167
            document.getElementById(\'extra_data_text\').style.display="none";
168
        }
169
    }
170
});
171
172
//Load user calendar
173
function load_calendar(user_id, month, year) {
174
    var url = "'.api_get_path(WEB_AJAX_PATH).'agenda.ajax.php?a=get_user_agenda&user_id=" +user_id + "&month="+month+"&year="+year;
175
    $(".modal-body").load(url);
176
}
177
</script>';
178
179
$this_section = SECTION_PLATFORM_ADMIN;
180
181
/**
182
 * Trim variable values to avoid trailing spaces.
183
 */
184
function trimVariables()
185
{
186
    $filterVariables = [
187
        'keyword',
188
        'keyword_firstname',
189
        'keyword_lastname',
190
        'keyword_username',
191
        'keyword_email',
192
        'keyword_officialcode',
193
    ];
194
195
    foreach ($filterVariables as $variable) {
196
        if (isset($_GET[$variable])) {
197
            $_GET[$variable] = trim($_GET[$variable]);
198
        }
199
    }
200
}
201
202
/**
203
 * Prepares the shared SQL query for the user table.
204
 * See get_user_data() and get_number_of_users().
205
 *
206
 * @param bool $getCount Whether to count, or get data
207
 *
208
 * @return string SQL query
209
 */
210
function prepare_user_sql_query($getCount)
211
{
212
    $sql = '';
213
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
214
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
215
216
    $isMultipleUrl = (api_is_platform_admin() || api_is_session_admin()) && api_get_multiple_access_url();
217
    $urlId = api_get_current_access_url_id();
218
219
    if ($getCount) {
220
        $sql .= "SELECT COUNT(u.id) AS total_number_of_items FROM $user_table u";
221
    } else {
222
        $sql .= 'SELECT u.id AS col0, u.official_code AS col2, ';
223
224
        if (api_is_western_name_order()) {
225
            $sql .= 'u.firstname AS col3, u.lastname AS col4, ';
226
        } else {
227
            $sql .= 'u.lastname AS col3, u.firstname AS col4, ';
228
        }
229
230
        // set columns name to sort
231
        if (api_get_setting('login_is_email') === 'true') {
232
            $sql .= " u.username AS col5,
233
                    u.email,
234
                    u.status AS col6,
235
                    u.active AS col7,
236
                    u.registration_date AS col8,
237
                    u.last_login as col9,
238
                    u.id AS col10,";
239
        } else {
240
            $sql .= " u.username AS col5,
241
                    u.email AS col6,
242
                    u.status AS col7,
243
                    u.active AS col8,
244
                    u.registration_date AS col9,
245
                    u.last_login as col10,
246
                    u.id AS col11,";
247
        }
248
        $sql .= "  u.expiration_date AS exp,
249
                   u.password
250
                FROM $user_table u";
251
    }
252
253
    // adding the filter to see the user's only of the current access_url
254
    if ($isMultipleUrl) {
255
        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
256
        $sql .= " INNER JOIN $access_url_rel_user_table url_rel_user
257
                  ON (u.id=url_rel_user.user_id)";
258
    }
259
260
    $classId = isset($_REQUEST['class_id']) && !empty($_REQUEST['class_id']) ? (int) $_REQUEST['class_id'] : 0;
261
262
    if ($classId) {
263
        $userGroupTable = Database::get_main_table(TABLE_USERGROUP_REL_USER);
264
        $sql .= " INNER JOIN $userGroupTable ug ON (ug.user_id = u.id)";
265
    }
266
267
    $keywordList = [
268
        'keyword_firstname',
269
        'keyword_lastname',
270
        'keyword_username',
271
        'keyword_email',
272
        'keyword_officialcode',
273
        'keyword_status',
274
        'keyword_active',
275
        'keyword_inactive',
276
        'check_easy_passwords',
277
    ];
278
279
    $keywordListValues = [];
280
    $atLeastOne = false;
281
    foreach ($keywordList as $keyword) {
282
        $keywordListValues[$keyword] = null;
283
        if (isset($_GET[$keyword]) && !empty($_GET[$keyword])) {
284
            $keywordListValues[$keyword] = $_GET[$keyword];
285
            $atLeastOne = true;
286
        }
287
    }
288
289
    if ($atLeastOne == false) {
290
        $keywordListValues = [];
291
    }
292
293
    if (isset($_GET['keyword']) && !empty($_GET['keyword'])) {
294
        $keywordFiltered = Database::escape_string("%".$_GET['keyword']."%");
295
        $sql .= " WHERE (
296
                    u.firstname LIKE '$keywordFiltered' OR
297
                    u.lastname LIKE '$keywordFiltered' OR
298
                    concat(u.firstname, ' ', u.lastname) LIKE '$keywordFiltered' OR
299
                    concat(u.lastname,' ',u.firstname) LIKE '$keywordFiltered' OR
300
                    u.username LIKE '$keywordFiltered' OR
301
                    u.official_code LIKE '$keywordFiltered' OR
302
                    u.email LIKE '$keywordFiltered'
303
                )
304
        ";
305
    } elseif (isset($keywordListValues) && !empty($keywordListValues)) {
306
        $query_admin_table = '';
307
        $keyword_admin = '';
308
309
        if (isset($keywordListValues['keyword_status']) &&
310
            $keywordListValues['keyword_status'] == PLATFORM_ADMIN
311
        ) {
312
            $query_admin_table = " , $admin_table a ";
313
            $keyword_admin = ' AND a.user_id = u.id ';
314
            $keywordListValues['keyword_status'] = '';
315
        }
316
317
        if ($keywordListValues['keyword_status'] === '%') {
318
            $keywordListValues['keyword_status'] = '';
319
        }
320
321
        $keyword_extra_value = '';
322
        $sql .= " $query_admin_table
323
            WHERE ( 1 = 1 ";
324
325
        if (!empty($keywordListValues['keyword_firstname'])) {
326
            $sql .= "AND u.firstname LIKE '".Database::escape_string("%".$keywordListValues['keyword_firstname']."%")."'";
327
        }
328
329
        if (!empty($keywordListValues['keyword_lastname'])) {
330
            $sql .= "AND u.lastname LIKE '".Database::escape_string("%".$keywordListValues['keyword_lastname']."%")."'";
331
        }
332
        if (!empty($keywordListValues['keyword_username'])) {
333
            $sql .= "AND u.username LIKE '".Database::escape_string("%".$keywordListValues['keyword_username']."%")."'";
334
        }
335
        if (!empty($keywordListValues['keyword_email'])) {
336
            $sql .= "AND u.email LIKE '".Database::escape_string("%".$keywordListValues['keyword_email']."%")."'";
337
        }
338
339
        if (!empty($keywordListValues['keyword_status'])) {
340
            $sql .= "AND u.status = '".Database::escape_string($keywordListValues['keyword_status'])."'";
341
        }
342
343
        if (!empty($keywordListValues['keyword_officialcode'])) {
344
            $sql .= " AND u.official_code LIKE '".Database::escape_string("%".$keywordListValues['keyword_officialcode']."%")."' ";
345
        }
346
347
        $sql .= " $keyword_admin $keyword_extra_value ";
348
349
        if (isset($keywordListValues['keyword_active']) &&
350
            !isset($keywordListValues['keyword_inactive'])
351
        ) {
352
            $sql .= ' AND u.active = 1';
353
        } elseif (isset($keywordListValues['keyword_inactive']) &&
354
            !isset($keywordListValues['keyword_active'])
355
        ) {
356
            $sql .= ' AND u.active = 0';
357
        }
358
        $sql .= ' ) ';
359
    }
360
361
    if ($classId) {
362
        $sql .= " AND ug.usergroup_id = $classId";
363
    }
364
365
    $preventSessionAdminsToManageAllUsers = api_get_setting('prevent_session_admins_to_manage_all_users');
366
367
    $extraConditions = '';
368
    if (api_is_session_admin() && $preventSessionAdminsToManageAllUsers === 'true') {
369
        $extraConditions .= ' AND u.creator_id = '.api_get_user_id();
370
    }
371
372
    // adding the filter to see the user's only of the current access_url
373
    if ($isMultipleUrl) {
374
        $extraConditions .= ' AND url_rel_user.access_url_id = '.$urlId;
375
    }
376
377
    $sql .= $extraConditions;
378
379
    $variables = Session::read('variables_to_show', []);
380
    $extraFields = api_get_configuration_value('user_search_on_extra_fields');
381
382
    if (!empty($extraFields) && isset($extraFields['extra_fields']) && isset($_GET['keyword'])) {
383
        $extraFieldList = $extraFields['extra_fields'];
384
        if (!empty($extraFieldList)) {
385
            foreach ($extraFieldList as $variable) {
386
                $_GET['extra_'.$variable] = Security::remove_XSS($_GET['keyword']);
387
            }
388
        }
389
        $variables = array_merge($extraFieldList, $variables);
390
    }
391
    if (!empty($variables)) {
392
        $extraField = new ExtraField('user');
393
        $extraFieldResult = [];
394
        $extraFieldHasData = [];
395
        foreach ($variables as $variable) {
396
            if (isset($_GET['extra_'.$variable])) {
397
                if (is_array($_GET['extra_'.$variable])) {
398
                    $values = $_GET['extra_'.$variable];
399
                } else {
400
                    $values = [$_GET['extra_'.$variable]];
401
                }
402
403
                if (empty($values)) {
404
                    continue;
405
                }
406
407
                $info = $extraField->get_handler_field_info_by_field_variable($variable);
408
409
                if (empty($info)) {
410
                    continue;
411
                }
412
413
                foreach ($values as $value) {
414
                    if (empty($value)) {
415
                        continue;
416
                    }
417
                    if ($info['field_type'] == ExtraField::FIELD_TYPE_TAG) {
418
                        $result = $extraField->getAllUserPerTag($info['id'], $value);
419
                        $result = empty($result) ? [] : array_column($result, 'user_id');
420
                    } else {
421
                        $result = UserManager::get_extra_user_data_by_value($variable, $value, true);
422
                    }
423
424
                    $extraFieldHasData[] = true;
425
                    if (!empty($result)) {
426
                        $extraFieldResult = array_merge($extraFieldResult, $result);
427
                    }
428
                }
429
            }
430
        }
431
432
        $condition = '  AND ';
433
        // If simple search then use "OR"
434
        if (isset($_GET['keyword']) && !empty($_GET['keyword'])) {
435
            $condition = ' OR ';
436
        }
437
438
        if (!empty($extraFieldHasData) && !empty($extraFieldResult)) {
439
            $sql .= " $condition (u.id IN ('".implode("','", $extraFieldResult)."') $extraConditions ) ";
440
        }
441
    }
442
443
    return $sql;
444
}
445
446
/**
447
 * Get the total number of users on the platform.
448
 *
449
 * @see SortableTable#get_total_number_of_items()
450
 */
451
function get_number_of_users()
452
{
453
    $sql = prepare_user_sql_query(true);
454
    $res = Database::query($sql);
455
    $obj = Database::fetch_object($res);
456
457
    return $obj->total_number_of_items;
458
}
459
460
/**
461
 * Get the users to display on the current page (fill the sortable-table).
462
 *
463
 * @param   int     offset of first user to recover
464
 * @param   int     Number of users to get
465
 * @param   int     Column to sort on
466
 * @param   string  Order (ASC,DESC)
467
 *
468
 * @return array Users list
469
 *
470
 * @see SortableTable#get_table_data($from)
471
 */
472
function get_user_data($from, $number_of_items, $column, $direction)
473
{
474
    $sql = prepare_user_sql_query(false);
475
    if (!in_array($direction, ['ASC', 'DESC'])) {
476
        $direction = 'ASC';
477
    }
478
    $column = (int) $column;
479
    $from = (int) $from;
480
    $number_of_items = (int) $number_of_items;
481
482
    $sql .= " ORDER BY col$column $direction ";
483
    $sql .= " LIMIT $from, $number_of_items";
484
485
    $res = Database::query($sql);
486
487
    $users = [];
488
    $t = time();
489
    while ($user = Database::fetch_array($res)) {
490
        $userPicture = UserManager::getUserPicture(
491
            $user[0],
492
            USER_IMAGE_SIZE_SMALL
493
        );
494
        $photo = '<img
495
            src="'.$userPicture.'" width="22" height="22"
496
            alt="'.api_get_person_name($user[2], $user[3]).'"
497
            title="'.api_get_person_name($user[2], $user[3]).'" />';
498
499
        if (1 == $user[7] && !empty($user['exp'])) {
500
            // check expiration date
501
            $expiration_time = convert_sql_date($user['exp']);
502
            // if expiration date is passed, store a special value for active field
503
            if ($expiration_time < $t) {
504
                $user[7] = '-1';
505
            }
506
        }
507
508
        // forget about the expiration date field
509
        $users[] = [
510
            $user[0], // id
511
            $photo,
512
            $user[1],
513
            $user[2],
514
            $user[3],
515
            $user[4], // username
516
            $user[5], // email
517
            $user[6],
518
            $user[7], // active
519
            api_get_local_time($user[8]),
520
            api_get_local_time($user[9], null, null, true),
521
            $user[0],
522
        ];
523
    }
524
525
    return $users;
526
}
527
528
/**
529
 * Returns a mailto-link.
530
 *
531
 * @param string $email An email-address
532
 *
533
 * @return string HTML-code with a mailto-link
534
 */
535
function email_filter($email)
536
{
537
    return Display::encrypted_mailto_link($email, cut($email, 26), 'small clickable_email_link');
538
}
539
540
/**
541
 * Returns a mailto-link.
542
 *
543
 * @param string $name
544
 * @param array  $params Deprecated
545
 * @param array  $row
546
 *
547
 * @return string HTML-code with a mailto-link
548
 */
549
function user_filter($name, $params, $row)
550
{
551
    $name = cut($name, 26);
552
553
    return '<a href="'.api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$row[0].'">'.$name.'</a>';
554
}
555
556
/**
557
 * Build the modify-column of the table.
558
 *
559
 * @param   int     The user id
560
 * @param   string  URL params to add to table links
561
 * @param   array   Row of elements to alter
562
 *
563
 * @throws Exception
564
 *
565
 * @return string Some HTML-code with modify-buttons
566
 */
567
function modify_filter($user_id, $url_params, $row)
568
{
569
    $_admins_list = Session::read('admin_list', []);
570
    $is_admin = in_array($user_id, $_admins_list);
571
    $statusname = api_get_status_langvars();
572
    $user_is_anonymous = false;
573
    $current_user_status_label = $row['7'];
574
575
    if ($current_user_status_label == $statusname[ANONYMOUS]) {
576
        $user_is_anonymous = true;
577
    }
578
    $result = '';
579
    if (!$user_is_anonymous) {
580
        $icon = Display::return_icon(
581
            'course.png',
582
            get_lang('Courses'),
583
            ['onmouseout' => 'clear_course_list (\'div_'.$user_id.'\')']
584
        );
585
        $result .= '<a href="javascript:void(0)" onclick="load_course_list(\'div_'.$user_id.'\','.$user_id.')" >
586
                    '.$icon.'
587
                    <div class="blackboard_hide" id="div_'.$user_id.'">&nbsp;&nbsp;</div>
588
                    </a>';
589
590
        $icon = Display::return_icon(
591
            'session.png',
592
            get_lang('Sessions'),
593
            ['onmouseout' => 'clear_session_list (\'div_s_'.$user_id.'\')']
594
        );
595
        $result .= '<a href="javascript:void(0)" onclick="load_session_list(\'div_s_'.$user_id.'\','.$user_id.')" >
596
                    '.$icon.'
597
                    <div class="blackboard_hide" id="div_s_'.$user_id.'">&nbsp;&nbsp;</div>
598
                    </a>';
599
    } else {
600
        $result .= Display::return_icon('course_na.png', get_lang('Courses')).'&nbsp;&nbsp;';
601
        $result .= Display::return_icon('course_na.png', get_lang('Sessions')).'&nbsp;&nbsp;';
602
    }
603
604
    if (api_is_platform_admin()) {
605
        if (!$user_is_anonymous) {
606
            $result .= '<a href="user_information.php?user_id='.$user_id.'">'.
607
                        Display::return_icon('info2.png', get_lang('Info')).'</a>&nbsp;&nbsp;';
608
        } else {
609
            $result .= Display::return_icon('info2_na.png', get_lang('Info')).'&nbsp;&nbsp;';
610
        }
611
    }
612
613
    // Only allow platform admins to login_as, or session admins only for students (not teachers nor other admins)
614
    $loginAsStatusForSessionAdmins = [$statusname[STUDENT]];
615
616
    // Except when allow_session_admin_login_as_teacher is enabled, then can login_as teachers also
617
    if (api_get_configuration_value('allow_session_admin_login_as_teacher')) {
618
        $loginAsStatusForSessionAdmins[] = $statusname[COURSEMANAGER];
619
    }
620
621
    $sessionAdminCanLoginAs = api_is_session_admin() &&
622
        in_array($current_user_status_label, $loginAsStatusForSessionAdmins);
623
624
    if (api_is_platform_admin() || $sessionAdminCanLoginAs) {
625
        if (!$user_is_anonymous) {
626
            if (api_global_admin_can_edit_admin($user_id, null, $sessionAdminCanLoginAs)) {
627
                $result .= '<a href="user_list.php?action=login_as&user_id='.$user_id.'&sec_token='.Security::getTokenFromSession().'">'.
628
                    Display::return_icon('login_as.png', get_lang('LoginAs')).'</a>&nbsp;';
629
            } else {
630
                $result .= Display::return_icon('login_as_na.png', get_lang('LoginAs')).'&nbsp;';
631
            }
632
        } else {
633
            $result .= Display::return_icon('login_as_na.png', get_lang('LoginAs')).'&nbsp;';
634
        }
635
    } else {
636
        $result .= Display::return_icon('login_as_na.png', get_lang('LoginAs')).'&nbsp;';
637
    }
638
639
    if ($current_user_status_label != $statusname[STUDENT]) {
640
        $result .= Display::return_icon(
641
            'statistics_na.png',
642
            get_lang('Reporting')
643
        ).'&nbsp;';
644
    } else {
645
        $result .= '<a href="../mySpace/myStudents.php?student='.$user_id.'">'.
646
            Display::return_icon('statistics.png', get_lang('Reporting')).
647
            '</a>&nbsp;';
648
    }
649
650
    if (api_is_platform_admin(true)) {
651
        $editProfileUrl = Display::getProfileEditionLink($user_id, true);
652
        if (!$user_is_anonymous &&
653
            api_global_admin_can_edit_admin($user_id, null, true)
654
        ) {
655
            $result .= '<a href="'.$editProfileUrl.'">'.
656
                Display::return_icon(
657
                    'edit.png',
658
                    get_lang('Edit'),
659
                    [],
660
                    ICON_SIZE_SMALL
661
                ).
662
                '</a>&nbsp;';
663
        } else {
664
            $result .= Display::return_icon(
665
                'edit_na.png',
666
                get_lang('Edit'),
667
                [],
668
                ICON_SIZE_SMALL
669
            ).'</a>&nbsp;';
670
        }
671
    }
672
673
    $allowAssignSkill = api_is_platform_admin(false, true);
674
675
    if ($allowAssignSkill) {
676
        $result .= Display::url(
677
            Display::return_icon(
678
                'skill-badges.png',
679
                get_lang('AssignSkill'),
680
                null,
681
                ICON_SIZE_SMALL
682
            ),
683
            api_get_path(WEB_CODE_PATH).'badge/assign.php?'.http_build_query(['user' => $user_id])
684
        );
685
    }
686
687
    if ($is_admin) {
688
        $result .= Display::return_icon(
689
            'admin_star.png',
690
            get_lang('IsAdministrator'),
691
            ['width' => ICON_SIZE_SMALL, 'heigth' => ICON_SIZE_SMALL]
692
        );
693
    } else {
694
        $result .= Display::return_icon(
695
            'admin_star_na.png',
696
            get_lang('IsNotAdministrator')
697
        );
698
    }
699
700
    // actions for assigning sessions, courses or users
701
    if (!api_is_session_admin()) {
702
        if ($current_user_status_label == $statusname[SESSIONADMIN]) {
703
            $result .= Display::url(
704
                Display::return_icon(
705
                    'view_more_stats.gif',
706
                    get_lang('AssignSessions')
707
                ),
708
                "dashboard_add_sessions_to_user.php?user={$user_id}"
709
            );
710
        } else {
711
            if ($current_user_status_label == $statusname[DRH] ||
712
                UserManager::is_admin($user_id) ||
713
                $current_user_status_label == $statusname[STUDENT_BOSS]
714
            ) {
715
                $result .= Display::url(
716
                    Display::return_icon(
717
                        'user_subscribe_course.png',
718
                        get_lang('AssignUsers'),
719
                        '',
720
                        ICON_SIZE_SMALL
721
                    ),
722
                    "dashboard_add_users_to_user.php?user={$user_id}"
723
                );
724
            }
725
726
            if ($current_user_status_label == $statusname[DRH] || UserManager::is_admin($user_id)) {
727
                $result .= Display::url(
728
                    Display::return_icon(
729
                        'course_add.gif',
730
                        get_lang('AssignCourses')
731
                    ),
732
                    "dashboard_add_courses_to_user.php?user={$user_id}"
733
                );
734
735
                $result .= Display::url(
736
                    Display::return_icon(
737
                        'view_more_stats.gif',
738
                        get_lang('AssignSessions')
739
                    ),
740
                    "dashboard_add_sessions_to_user.php?user={$user_id}"
741
                );
742
            }
743
        }
744
    }
745
746
    $allowDelete = api_get_configuration_value('allow_delete_user_for_session_admin');
747
748
    if (api_is_session_admin() && $allowDelete) {
749
        if ($user_id != api_get_user_id() &&
750
            !$user_is_anonymous &&
751
            api_global_admin_can_edit_admin($user_id, null, true)
752
        ) {
753
            // you cannot lock yourself out otherwise you could disable all the accounts including your own => everybody is locked out and nobody can change it anymore.
754
            $result .= ' <a href="user_list.php?action=delete_user&user_id='.$user_id.'&'.$url_params.'&sec_token='.Security::getTokenFromSession().'"  onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice")))."'".')) return false;">'.
755
                Display::return_icon(
756
                    'delete.png',
757
                    get_lang('Delete'),
758
                    [],
759
                    ICON_SIZE_SMALL
760
                ).
761
                '</a>';
762
        }
763
    }
764
    if (api_is_platform_admin()) {
765
        $result .= ' <a data-title="'.get_lang('FreeBusyCalendar').'" href="'.api_get_path(WEB_AJAX_PATH).'agenda.ajax.php?a=get_user_agenda&user_id='.$user_id.'&modal_size=lg" class="agenda_opener ajax">'.
766
            Display::return_icon(
767
                'calendar.png',
768
                get_lang('FreeBusyCalendar'),
769
                [],
770
                ICON_SIZE_SMALL
771
            ).
772
            '</a>';
773
774
        if ($user_id != api_get_user_id() &&
775
            !$user_is_anonymous &&
776
            api_global_admin_can_edit_admin($user_id)
777
        ) {
778
            $result .= ' <a href="user_list.php?action=anonymize&user_id='.$user_id.'&'.$url_params.'&sec_token='.Security::getTokenFromSession().'"  onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice")))."'".')) return false;">'.
779
                Display::return_icon(
780
                    'anonymous.png',
781
                    get_lang('Anonymize'),
782
                    [],
783
                    ICON_SIZE_SMALL
784
                ).
785
                '</a>';
786
        }
787
788
        $deleteAllowed = !api_get_configuration_value('deny_delete_users');
789
        if ($deleteAllowed) {
790
            if ($user_id != api_get_user_id() &&
791
                !$user_is_anonymous &&
792
                api_global_admin_can_edit_admin($user_id)
793
            ) {
794
                // you cannot lock yourself out otherwise you could disable all the accounts
795
                // including your own => everybody is locked out and nobody can change it anymore.
796
                $result .= ' <a href="user_list.php?action=delete_user&user_id='.$user_id.'&'.$url_params.'&sec_token='.Security::getTokenFromSession().'"  onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice")))."'".')) return false;">'.
797
                    Display::return_icon(
798
                        'delete.png',
799
                        get_lang('Delete'),
800
                        [],
801
                        ICON_SIZE_SMALL
802
                    ).
803
                    '</a>';
804
            } else {
805
                $result .= Display::return_icon(
806
                    'delete_na.png',
807
                    get_lang('Delete'),
808
                    [],
809
                    ICON_SIZE_SMALL
810
                );
811
            }
812
        }
813
    }
814
815
    return '<div style="width:205px">'.$result.'</div>';
816
}
817
818
/**
819
 * Build the active-column of the table to lock or unlock a certain user
820
 * lock = the user can no longer use this account.
821
 *
822
 * @author Patrick Cool <[email protected]>, Ghent University
823
 *
824
 * @param int    $active the current state of the account
825
 * @param string $params
826
 * @param array  $row
827
 *
828
 * @return string Some HTML-code with the lock/unlock button
829
 */
830
function active_filter($active, $params, $row)
831
{
832
    $_user = api_get_user_info();
833
834
    if ('1' == $active) {
835
        $action = 'Lock';
836
        $image = 'accept';
837
    } elseif ('-1' == $active) {
838
        $action = 'edit';
839
        $image = 'warning';
840
    } elseif ('0' == $active) {
841
        $action = 'Unlock';
842
        $image = 'error';
843
    }
844
845
    $result = '';
846
847
    if ('edit' === $action) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $action does not seem to be defined for all execution paths leading up to this point.
Loading history...
848
        $result = Display::return_icon(
849
            $image.'.png',
850
            get_lang('AccountExpired'),
851
            [],
852
            16
853
        );
854
    } elseif ($row['0'] != $_user['user_id']) {
855
        // you cannot lock yourself out otherwise you could disable all the
856
        // accounts including your own => everybody is locked out and nobody
857
        // can change it anymore.
858
        $result = Display::return_icon(
859
            $image.'.png',
860
            get_lang(ucfirst($action)),
861
            ['onclick' => 'active_user(this);', 'id' => 'img_'.$row['0']],
862
            16
863
        );
864
    }
865
866
    return $result;
867
}
868
869
/**
870
 * Instead of displaying the integer of the status, we give a translation for the status.
871
 *
872
 * @param int $status
873
 *
874
 * @return string translation
875
 *
876
 * @version march 2008
877
 *
878
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
879
 */
880
function status_filter($status)
881
{
882
    $name = api_get_status_langvars();
883
884
    return $name[$status];
885
}
886
887
if (isset($_GET['keyword']) || isset($_GET['keyword_firstname'])) {
888
    $interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('PlatformAdmin')];
889
    $interbreadcrumb[] = ['url' => 'user_list.php', 'name' => get_lang('UserList')];
890
    $tool_name = get_lang('SearchUsers');
891
} else {
892
    $interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('PlatformAdmin')];
893
    $tool_name = get_lang('UserList');
894
}
895
896
$message = '';
897
898
if (!empty($action)) {
899
    $check = Security::check_token('get');
900
    if ($check) {
901
        switch ($action) {
902
            case 'add_user_to_my_url':
903
                $user_id = $_REQUEST['user_id'];
904
                $result = UrlManager::add_user_to_url($user_id, $urlId);
905
                if ($result) {
906
                    $user_info = api_get_user_info($user_id);
907
                    $message = get_lang('UserAdded').' '.$user_info['complete_name_with_username'];
908
                    $message = Display::return_message($message, 'confirmation');
909
                }
910
                break;
911
            case 'delete_user':
912
                $message = UserManager::deleteUserWithVerification($_GET['user_id']);
913
                Display::addFlash($message);
914
                header('Location: '.api_get_self());
915
                exit;
916
                break;
917
            case 'delete':
918
                if (api_is_platform_admin() && !empty($_POST['id'])) {
919
                    $number_of_selected_users = count($_POST['id']);
920
                    $number_of_affected_users = 0;
921
                    if (is_array($_POST['id'])) {
922
                        foreach ($_POST['id'] as $index => $user_id) {
923
                            if ($user_id != $_user['user_id']) {
924
                                if (UserManager::delete_user($user_id)) {
925
                                    $number_of_affected_users++;
926
                                }
927
                            }
928
                        }
929
                    }
930
                    if ($number_of_selected_users == $number_of_affected_users) {
931
                        $message = Display::return_message(
932
                            get_lang('SelectedUsersDeleted'),
933
                            'confirmation'
934
                        );
935
                    } else {
936
                        $message = Display::return_message(
937
                            get_lang('SomeUsersNotDeleted'),
938
                            'error'
939
                        );
940
                    }
941
                }
942
                break;
943
            case 'disable':
944
                if (api_is_platform_admin()) {
945
                    $number_of_selected_users = count($_POST['id']);
946
                    $number_of_affected_users = 0;
947
                    if (is_array($_POST['id'])) {
948
                        foreach ($_POST['id'] as $index => $user_id) {
949
                            if ($user_id != $_user['user_id']) {
950
                                if (UserManager::disable($user_id)) {
951
                                    $number_of_affected_users++;
952
                                }
953
                            }
954
                        }
955
                    }
956
                    if ($number_of_selected_users == $number_of_affected_users) {
957
                        $message = Display::return_message(
958
                            get_lang('SelectedUsersDisabled'),
959
                            'confirmation'
960
                        );
961
                    } else {
962
                        $message = Display::return_message(
963
                            get_lang('SomeUsersNotDisabled'),
964
                            'error'
965
                        );
966
                    }
967
                }
968
                break;
969
            case 'enable':
970
                if (api_is_platform_admin()) {
971
                    $number_of_selected_users = count($_POST['id']);
972
                    $number_of_affected_users = 0;
973
                    if (is_array($_POST['id'])) {
974
                        foreach ($_POST['id'] as $index => $user_id) {
975
                            if ($user_id != $_user['user_id']) {
976
                                if (UserManager::enable($user_id)) {
977
                                    $number_of_affected_users++;
978
                                }
979
                            }
980
                        }
981
                    }
982
                    if ($number_of_selected_users == $number_of_affected_users) {
983
                        $message = Display::return_message(
984
                            get_lang('SelectedUsersEnabled'),
985
                            'confirmation'
986
                        );
987
                    } else {
988
                        $message = Display::return_message(
989
                            get_lang('SomeUsersNotEnabled'),
990
                            'error'
991
                        );
992
                    }
993
                }
994
                break;
995
            case 'anonymize':
996
                $message = UserManager::anonymizeUserWithVerification($_GET['user_id']);
997
                Display::addFlash($message);
998
                header('Location: '.api_get_self());
999
                exit;
1000
                break;
1001
        }
1002
        Security::clear_token();
1003
    }
1004
}
1005
1006
// Create a search-box
1007
$form = new FormValidator('search_simple', 'get', null, null, null, 'inline');
1008
$form->addText(
1009
    'keyword',
1010
    get_lang('Search'),
1011
    false,
1012
    [
1013
        'aria-label' => get_lang('SearchUsers'),
1014
    ]
1015
);
1016
$form->addButtonSearch(get_lang('Search'));
1017
1018
$searchAdvanced = '
1019
<a id="advanced_params" href="javascript://"
1020
    class="btn btn-default advanced_options" onclick="display_advanced_search_form();">
1021
    <span id="img_plus_and_minus">&nbsp;
1022
    '.Display::returnFontAwesomeIcon('arrow-right').' '.get_lang('AdvancedSearch').'
1023
    </span>
1024
</a>';
1025
$actionsLeft = '';
1026
$actionsCenter = '';
1027
$actionsRight = '';
1028
if (api_is_platform_admin()) {
1029
    $actionsRight .= '<a class="pull-right" href="'.api_get_path(WEB_CODE_PATH).'admin/user_add.php">'.
1030
         Display::return_icon('new_user.png', get_lang('AddUsers'), '', ICON_SIZE_MEDIUM).'</a>';
1031
}
1032
1033
$actionsLeft .= $form->returnForm();
1034
$actionsCenter .= $searchAdvanced;
1035
1036
if (isset($_GET['keyword'])) {
1037
    $parameters = ['keyword' => Security::remove_XSS($_GET['keyword'])];
1038
} elseif (isset($_GET['keyword_firstname'])) {
1039
    $parameters['keyword_firstname'] = Security::remove_XSS($_GET['keyword_firstname']);
1040
    $parameters['keyword_lastname'] = Security::remove_XSS($_GET['keyword_lastname']);
1041
    $parameters['keyword_username'] = Security::remove_XSS($_GET['keyword_username']);
1042
    $parameters['keyword_email'] = Security::remove_XSS($_GET['keyword_email']);
1043
    $parameters['keyword_officialcode'] = Security::remove_XSS($_GET['keyword_officialcode']);
1044
    $parameters['keyword_status'] = Security::remove_XSS($_GET['keyword_status']);
1045
    if (isset($_GET['keyword_active'])) {
1046
        $parameters['keyword_active'] = Security::remove_XSS($_GET['keyword_active']);
1047
    }
1048
    if (isset($_GET['keyword_inactive'])) {
1049
        $parameters['keyword_inactive'] = Security::remove_XSS($_GET['keyword_inactive']);
1050
    }
1051
}
1052
// Create a sortable table with user-data
1053
$parameters['sec_token'] = Security::get_token();
1054
1055
$_admins_list = array_keys(UserManager::get_all_administrators());
1056
Session::write('admin_list', $_admins_list);
1057
// Display Advanced search form.
1058
$form = new FormValidator(
1059
    'advanced_search',
1060
    'get',
1061
    '',
1062
    '',
1063
    [],
1064
    FormValidator::LAYOUT_HORIZONTAL
1065
);
1066
1067
$form->addElement('html', '<div id="advanced_search_form" style="display:none;">');
1068
$form->addElement('header', get_lang('AdvancedSearch'));
1069
$form->addText('keyword_firstname', get_lang('FirstName'), false);
1070
$form->addText('keyword_lastname', get_lang('LastName'), false);
1071
$form->addText('keyword_username', get_lang('LoginName'), false);
1072
$form->addText('keyword_email', get_lang('Email'), false);
1073
$form->addText('keyword_officialcode', get_lang('OfficialCode'), false);
1074
1075
$classId = isset($_REQUEST['class_id']) && !empty($_REQUEST['class_id']) ? (int) $_REQUEST['class_id'] : 0;
1076
$options = [];
1077
if ($classId) {
1078
    $userGroup = new UserGroup();
1079
    $groupInfo = $userGroup->get($classId);
1080
    if ($groupInfo) {
1081
        $options = [$classId => $groupInfo['name']];
1082
    }
1083
}
1084
$form->addSelectAjax(
1085
    'class_id',
1086
    get_lang('SocialGroup').' / '.get_lang('Class'),
1087
    $options,
1088
    ['url' => api_get_path(WEB_AJAX_PATH).'usergroup.ajax.php?a=get_class_by_keyword']
1089
);
1090
1091
$status_options = [];
1092
$status_options['%'] = get_lang('All');
1093
$status_options[STUDENT] = get_lang('Student');
1094
$status_options[COURSEMANAGER] = get_lang('Teacher');
1095
$status_options[DRH] = get_lang('Drh');
1096
$status_options[SESSIONADMIN] = get_lang('SessionsAdmin');
1097
$status_options[PLATFORM_ADMIN] = get_lang('Administrator');
1098
1099
$form->addElement(
1100
    'select',
1101
    'keyword_status',
1102
    get_lang('Profile'),
1103
    $status_options
1104
);
1105
1106
$active_group = [];
1107
$active_group[] = $form->createElement('checkbox', 'keyword_active', '', get_lang('Active'));
1108
$active_group[] = $form->createElement('checkbox', 'keyword_inactive', '', get_lang('Inactive'));
1109
$form->addGroup($active_group, '', get_lang('ActiveAccount'), null, false);
1110
$form->addElement('checkbox', 'check_easy_passwords', null, get_lang('CheckEasyPasswords'));
1111
$data = $extraField->addElements($form, 0, [], true, false, $variablesToShow);
1112
1113
$htmlHeadXtra[] = '
1114
    <script>
1115
    $(function () {
1116
        '.$data['jquery_ready_content'].'
1117
    })
1118
    </script>
1119
';
1120
1121
$form->addButtonSearch(get_lang('SearchUsers'));
1122
1123
$defaults = [];
1124
$defaults['keyword_active'] = 1;
1125
$defaults['keyword_inactive'] = 1;
1126
$form->setDefaults($defaults);
1127
$form->addElement('html', '</div>');
1128
1129
$form = $form->returnForm();
1130
1131
$table = new SortableTable(
1132
    'users',
1133
    'get_number_of_users',
1134
    'get_user_data',
1135
    (api_is_western_name_order() xor api_sort_by_first_name()) ? 3 : 2,
1136
    20,
1137
    'ASC',
1138
    null,
1139
    ['style' => 'font-size: 1.4rem;', 'class' => 'table table-hover table-striped table-bordered table-condensed']
1140
);
1141
$table->set_additional_parameters($parameters);
1142
$table->set_header(0, '&nbsp;', false);
1143
$table->set_header(1, get_lang('Photo'), false);
1144
$table->set_header(2, get_lang('OfficialCode'));
1145
1146
if (api_is_western_name_order()) {
1147
    $table->set_header(3, get_lang('FirstName'));
1148
    $table->set_header(4, get_lang('LastName'));
1149
} else {
1150
    $table->set_header(3, get_lang('LastName'));
1151
    $table->set_header(4, get_lang('FirstName'));
1152
}
1153
$table->set_header(5, get_lang('LoginName'));
1154
$table->set_header(6, get_lang('Email'));
1155
$table->set_header(7, get_lang('Profile'));
1156
$table->set_header(8, get_lang('Active'));
1157
$table->set_header(9, get_lang('RegistrationDate'));
1158
$table->set_header(10, get_lang('LatestLogin'));
1159
$table->set_header(11, get_lang('Action'), false);
1160
1161
$table->set_column_filter(3, 'user_filter');
1162
$table->set_column_filter(4, 'user_filter');
1163
$table->set_column_filter(6, 'email_filter');
1164
$table->set_column_filter(7, 'status_filter');
1165
$table->set_column_filter(8, 'active_filter');
1166
$table->set_column_filter(11, 'modify_filter');
1167
1168
// Hide email column if login is email, to avoid column with same data
1169
if (api_get_setting('login_is_email') === 'true') {
1170
    $table->setHideColumn(6);
1171
}
1172
1173
// Only show empty actions bar if delete users has been blocked
1174
$actionsList = [];
1175
if (api_is_platform_admin() &&
1176
    !api_get_configuration_value('deny_delete_users')
1177
) {
1178
    $actionsList['delete'] = get_lang('DeleteFromPlatform');
1179
}
1180
$actionsList['disable'] = get_lang('Disable');
1181
$actionsList['enable'] = get_lang('Enable');
1182
$table->set_form_actions($actionsList);
1183
1184
$table_result = $table->return_table();
1185
$extra_search_options = '';
1186
1187
// Try to search the user everywhere
1188
if (0 == $table->get_total_number_of_items()) {
1189
    if (api_get_multiple_access_url() && isset($_REQUEST['keyword'])) {
1190
        $keyword = Database::escape_string($_REQUEST['keyword']);
1191
        $conditions = ['username' => $keyword];
1192
        $user_list = UserManager::get_user_list(
1193
            $conditions,
1194
            [],
1195
            false,
1196
            ' OR '
1197
        );
1198
        if (!empty($user_list)) {
1199
            $extra_search_options = Display::page_subheader(get_lang('UsersFoundInOtherPortals'));
1200
1201
            $table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
1202
            $column = 0;
1203
            $row = 0;
1204
            $headers = [get_lang('User'), 'URL', get_lang('Actions')];
1205
            foreach ($headers as $header) {
1206
                $table->setHeaderContents($row, $column, $header);
1207
                $column++;
1208
            }
1209
            $row++;
1210
1211
            foreach ($user_list as $user) {
1212
                $column = 0;
1213
                $access_info = UrlManager::get_access_url_from_user($user['id']);
1214
                $access_info_to_string = '';
1215
                $add_user = true;
1216
                if (!empty($access_info)) {
1217
                    foreach ($access_info as $url_info) {
1218
                        if ($urlId == $url_info['access_url_id']) {
1219
                            $add_user = false;
1220
                        }
1221
                        $access_info_to_string .= $url_info['url'].'<br />';
1222
                    }
1223
                }
1224
                if ($add_user) {
1225
                    $row_table = [];
1226
                    $row_table[] = api_get_person_name($user['firstname'], $user['lastname']).' ('.$user['username'].') ';
1227
                    $row_table[] = $access_info_to_string;
1228
                    $url = api_get_self().'?action=add_user_to_my_url&user_id='.$user['id'].'&sec_token='.Security::getTokenFromSession();
1229
                    $row_table[] = Display::url(
1230
                        get_lang('AddUserToMyURL'),
1231
                        $url,
1232
                        ['class' => 'btn']
1233
                    );
1234
1235
                    foreach ($row_table as $cell) {
1236
                        $table->setCellContents($row, $column, $cell);
1237
                        $table->updateCellAttributes(
1238
                            $row,
1239
                            $column,
1240
                            'align="center"'
1241
                        );
1242
                        $column++;
1243
                    }
1244
                    $row++;
1245
                }
1246
            }
1247
            $extra_search_options .= $table->toHtml();
1248
            $table_result = '';
1249
        }
1250
    }
1251
}
1252
$toolbarActions = Display::toolbarAction(
1253
    'toolbarUser',
1254
    [$actionsLeft, $actionsCenter, $actionsRight],
1255
    [4, 4, 4]
1256
);
1257
1258
$tpl = new Template($tool_name);
1259
$tpl->assign('actions', $toolbarActions);
1260
$tpl->assign('message', $message);
1261
$tpl->assign('content', $form.$table_result.$extra_search_options);
1262
$tpl->display_one_col_template();
1263