From ccbdf107685f96c122462598bfe79aa5022d16a1 Mon Sep 17 00:00:00 2001 From: Christian Beeznest Date: Fri, 31 Jan 2025 00:47:50 -0500 Subject: [PATCH] User: add advanced user edition with bulk and ajax updates - refs BT#22305 --- main/admin/index.php | 10 + main/admin/user_advanced_edit.php | 330 ++++++++++++++++++++++++++++ main/inc/ajax/user_manager.ajax.php | 80 +++++++ main/inc/lib/usermanager.lib.php | 48 ++++ 4 files changed, 468 insertions(+) create mode 100644 main/admin/user_advanced_edit.php diff --git a/main/admin/index.php b/main/admin/index.php index 4398b0e02bc..e4860c87ec1 100644 --- a/main/admin/index.php +++ b/main/admin/index.php @@ -147,6 +147,11 @@ 'url' => 'usergroups.php', 'label' => get_lang('Classes'), ]; + $items[] = [ + 'class' => 'item-user-advanced_edit', + 'url' => 'user_advanced_edit.php', + 'label' => get_lang('UserAdvancedEdit'), + ]; if (api_get_configuration_value('show_link_request_hrm_user')) { $items[] = [ 'class' => 'item-user-linking-requests', @@ -177,6 +182,11 @@ 'label' => get_lang('Classes'), ], ]; + $items[] = [ + 'class' => 'item-user-advanced_edit', + 'url' => 'user_advanced_edit.php', + 'label' => get_lang('UserAdvancedEdit'), + ]; if (api_is_session_admin()) { if ('true' === api_get_setting('limit_session_admin_role')) { diff --git a/main/admin/user_advanced_edit.php b/main/admin/user_advanced_edit.php new file mode 100644 index 00000000000..0ff0ea53300 --- /dev/null +++ b/main/admin/user_advanced_edit.php @@ -0,0 +1,330 @@ + $value) { + $parameters[$key] = Security::remove_XSS($value); + } +} + +$interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('PlatformAdmin')]; + +// Toolbar actions +$toolbarActions = ''; + +// Advanced search form +$form = new FormValidator('advancedSearch', 'get', '', '', [], FormValidator::LAYOUT_HORIZONTAL); +$form->addElement('header', '', get_lang('AdvancedSearch')); +$form->addText('keywordUsername', get_lang('LoginName'), false); +$form->addText('keywordEmail', get_lang('Email'), false); +$form->addText('keywordFirstname', get_lang('FirstName'), false); +$form->addText('keywordLastname', get_lang('LastName'), false); +$form->addText('keywordOfficialCode', get_lang('OfficialCode'), false); + +$statusOptions = [ + '%' => get_lang('All'), + STUDENT => get_lang('Student'), + COURSEMANAGER => get_lang('Teacher'), + DRH => get_lang('Drh'), + SESSIONADMIN => get_lang('SessionsAdmin'), + PLATFORM_ADMIN => get_lang('Administrator') +]; +$form->addElement('select', 'keywordStatus', get_lang('Profile'), $statusOptions); + +$activeGroup = []; +$activeGroup[] = $form->createElement('checkbox', 'keywordActive', '', get_lang('Active')); +$activeGroup[] = $form->createElement('checkbox', 'keywordInactive', '', get_lang('Inactive')); +$form->addGroup($activeGroup, '', get_lang('ActiveAccount'), null, false); +$form->addButtonSearch(get_lang('SearchUsers'), 'filter'); + +// Search filters +$searchFilters = [ + 'keywordFirstname' => $_GET['keywordFirstname'] ?? '', + 'keywordLastname' => $_GET['keywordLastname'] ?? '', + 'keywordUsername' => $_GET['keywordUsername'] ?? '', + 'keywordEmail' => $_GET['keywordEmail'] ?? '', + 'keywordOfficialCode' => $_GET['keywordOfficialCode'] ?? '', + 'keywordStatus' => $_GET['keywordStatus'] ?? '', + 'keywordActive' => $_GET['keywordActive'] ?? '', + 'keywordInactive' => $_GET['keywordInactive'] ?? '', +]; + +$users = []; +if (isset($_GET['filter'])) { + $users = UserManager::searchUsers($searchFilters); +} + +$fieldSelector = ''; +$jqueryReadyContent = ''; +$extraUserField = new ExtraField('user'); +if (!empty($users)) { + $extraFields = $extraUserField->get_all(['filter = ?' => 1], 'option_order'); + + $editableFields = [ + 'firstname' => get_lang('FirstName'), + 'lastname' => get_lang('LastName'), + 'email' => get_lang('Email'), + 'phone' => get_lang('PhoneNumber'), + 'official_code' => get_lang('OfficialCode'), + 'status' => get_lang('Profile'), + 'active' => get_lang('ActiveAccount'), + 'password' => get_lang('Password') + ]; + + foreach ($extraFields as $field) { + $editableFields[$field['variable']] = ucfirst($field['variable']); + } + + $form->addElement('select', 'editableFields', get_lang('FieldsToEdit'), $editableFields, [ + 'multiple' => 'multiple', + 'size' => 7 + ]); + $form->addElement('submit', 'filter', get_lang('Filter')); +} + +$tableResult = ''; +if (!empty($users)) { + $selectedFields = $_GET['editableFields'] ?? []; + + foreach ($users as &$user) { + $userData = api_get_user_info($user['id']); + if ($userData) { + $user = array_merge($user, $userData); + } + + $extraFieldValues = new ExtraFieldValue('user'); + $userExtraFields = $extraFieldValues->getAllValuesByItem($user['id']); + + $formattedExtraFields = []; + foreach ($userExtraFields as $extraField) { + $formattedExtraFields[$extraField['variable']] = $extraField['value']; + } + + $user['extra_fields'] = $formattedExtraFields; + } + unset($user); + + $userTable = new SortableTable('users', null, null, 0, 50); + $userTable->set_header(0, get_lang('ID')); + $userTable->set_header(1, get_lang('Username')); + + foreach ($selectedFields as $field) { + $userTable->set_header(count($userTable->headers), ucfirst($field)); + } + + $userTable->set_header(count($userTable->headers), get_lang('Actions')); + + foreach ($users as $user) { + $row = [$user['id'], $user['username']]; + + foreach ($selectedFields as $field) { + $value = isset($user[$field]) ? htmlspecialchars($user[$field]) : ''; + + $extraFieldTypes = []; + foreach ($extraFields as $extraField) { + $extraFieldTypes[$extraField['variable']] = $extraField['field_type']; + } + + if (isset($user['extra_fields'][$field])) { + $fieldType = $extraFieldTypes[$field] ?? ExtraField::FIELD_TYPE_TEXT; + $value = htmlspecialchars($user['extra_fields'][$field]); + + switch ($fieldType) { + case ExtraField::FIELD_TYPE_TEXTAREA: + $row[] = ''; + break; + + case ExtraField::FIELD_TYPE_SELECT: + $fieldHtml = ''; + $row[] = $fieldHtml; + break; + + case ExtraField::FIELD_TYPE_CHECKBOX: + $checked = ($value == '1') ? 'checked' : ''; + $row[] = ''; + break; + + case ExtraField::FIELD_TYPE_RADIO: + $fieldHtml = ''; + foreach ($extraField['options'] as $option) { + $checked = ($option['option_value'] == $value) ? 'checked' : ''; + $fieldHtml .= ''; + } + $row[] = $fieldHtml; + break; + + case ExtraField::FIELD_TYPE_TAG: + + $extraTagField = $extraUserField->get_handler_field_info_by_field_variable($field); + $formattedValue = UserManager::get_user_tags_to_string( + $user['id'], + $extraTagField['id'], + false + ); + + $row[] = ''. + ''.get_lang('KeywordTip').''; + break; + + case ExtraField::FIELD_TYPE_DOUBLE_SELECT: + if (is_array($value) && isset($value["extra_{$field}"]) && isset($value["extra_{$field}_second"])) { + $formattedValue = $value["extra_{$field}"] . ',' . $value["extra_{$field}_second"]; + } else { + $formattedValue = ''; + } + $row[] = ''. + ''.get_lang('KeywordTip').''; + break; + + default: + $row[] = ''; + break; + } + } + else { + if ($field === 'password') { + $row[] = ''; + } + elseif ($field === 'status') { + $statusOptions = [ + STUDENT => get_lang('Student'), + COURSEMANAGER => get_lang('Teacher'), + DRH => get_lang('Drh'), + SESSIONADMIN => get_lang('SessionsAdmin'), + PLATFORM_ADMIN => get_lang('Administrator') + ]; + $select = ''; + $row[] = $select; + } + elseif ($field === 'active') { + $checkedActive = ($user['active'] == 1) ? 'checked' : ''; + $checkedInactive = ($user['active'] == 0) ? 'checked' : ''; + $row[] = ' + '; + } + else { + $row[] = ''; + } + } + } + + $row[] = ''; + + $userTable->addRow($row); + } + + $tableResult = $userTable->return_table(); +} + +$htmlHeadXtra[] = ''; + +$formContent = $form->returnForm(); + +// Render page +$tpl = new Template($tool_name); +$tpl->assign('actions', $toolbarActions); +$tpl->assign('message', $message); +$tpl->assign('content', $formContent . $fieldSelector . $tableResult . (!empty($users) ? '' : '')); +$tpl->display_one_col_template(); diff --git a/main/inc/ajax/user_manager.ajax.php b/main/inc/ajax/user_manager.ajax.php index 410e628adba..5127b58f641 100755 --- a/main/inc/ajax/user_manager.ajax.php +++ b/main/inc/ajax/user_manager.ajax.php @@ -463,6 +463,86 @@ header('Content-Type: application/json'); echo json_encode(['items' => $items]); break; + case 'update_users': + $usersData = json_decode($_POST['users'], true); + $updatedCount = 0; + + foreach ($usersData as $userData) { + if (empty($userData['user_id'])) { + continue; + } + + $userId = (int) $userData['user_id']; + $currentUserData = api_get_user_info($userId); + + if (!$currentUserData) { + continue; + } + + $updatedData = [ + 'firstname' => $userData['firstname'] ?? $currentUserData['firstname'], + 'lastname' => $userData['lastname'] ?? $currentUserData['lastname'], + 'email' => $userData['email'] ?? $currentUserData['email'], + 'phone' => $userData['phone'] ?? $currentUserData['phone'], + 'official_code' => $userData['official_code'] ?? $currentUserData['official_code'], + 'status' => isset($userData['status']) ? (int) $userData['status'] : $currentUserData['status'], + 'active' => isset($userData['active']) ? (int) $userData['active'] : $currentUserData['active'], + ]; + + if (!empty($userData['password'])) { + $updatedData['password'] = $userData['password']; + } + + $extraFieldHandler = new ExtraField('user'); + $extraFieldValue = new ExtraFieldValue('user'); + $extraFields = []; + foreach ($userData as $key => &$value) { + if (strpos($key, 'extra_') === 0) { + $fieldName = str_replace('extra_', '', $key); + $fieldInfo = $extraFieldHandler->get_handler_field_info_by_field_variable($fieldName); + if ($fieldInfo) { + if ($fieldInfo['field_type'] == 10 && is_string($value) && strpos($value, ',') !== false) { + $value = explode(',', $value); + } + } + } + } + + UserManager::update_user( + $userId, + $updatedData['firstname'], + $updatedData['lastname'], + $currentUserData['username'], + $updatedData['password'] ?? null, + $currentUserData['auth_source'], + $updatedData['email'], + $updatedData['status'], + $updatedData['official_code'], + $updatedData['phone'], + $currentUserData['picture_uri'], + null, + $updatedData['active'], + null, + null, + null, + $currentUserData['language'] + ); + + $userData['item_id'] = $userId; + $extraFieldValue->saveFieldValues( + $userData, + false, + false, + [], + [], + true + ); + + $updatedCount++; + } + + echo json_encode(['message' => $updatedCount.' '.get_lang('UsersAdded')]); + break; default: echo ''; } diff --git a/main/inc/lib/usermanager.lib.php b/main/inc/lib/usermanager.lib.php index 0504323f5e5..0c4aadee299 100755 --- a/main/inc/lib/usermanager.lib.php +++ b/main/inc/lib/usermanager.lib.php @@ -8261,4 +8261,52 @@ private static function getGravatar( return $url; } + + /** + * Search for users based on given filters. + */ + public static function searchUsers(array $filters = [], array $editableFields = []): array + { + $where = []; + + if (!empty($filters['keywordFirstname'])) { + $where[] = "u.firstname LIKE '%".Database::escape_string($filters['keywordFirstname'])."%'"; + } + if (!empty($filters['keywordLastname'])) { + $where[] = "u.lastname LIKE '%".Database::escape_string($filters['keywordLastname'])."%'"; + } + if (!empty($filters['keywordUsername'])) { + $where[] = "u.username LIKE '%".Database::escape_string($filters['keywordUsername'])."%'"; + } + if (!empty($filters['keywordEmail'])) { + $where[] = "u.email LIKE '%".Database::escape_string($filters['keywordEmail'])."%'"; + } + if (!empty($filters['keywordOfficialCode'])) { + $where[] = "u.official_code LIKE '%".Database::escape_string($filters['keywordOfficialCode'])."%'"; + } + if (!empty($filters['keywordStatus']) && $filters['keywordStatus'] !== '%') { + $where[] = "u.status = '".Database::escape_string($filters['keywordStatus'])."'"; + } + if (!empty($filters['keywordActive']) && empty($filters['keywordInactive'])) { + $where[] = "u.active = 1"; + } elseif (empty($filters['keywordActive']) && !empty($filters['keywordInactive'])) { + $where[] = "u.active = 0"; + } + + $fields = ['u.id', 'u.username']; + + if (!empty($editableFields)) { + foreach ($editableFields as $field) { + $fields[] = "u." . Database::escapeField($field); + } + } + + $sql = "SELECT " . implode(", ", $fields) . " FROM " . Database::get_main_table(TABLE_MAIN_USER) . " u"; + if (!empty($where)) { + $sql .= " WHERE " . implode(" AND ", $where); + } + $sql .= " ORDER BY u.id ASC"; + + return Database::store_result(Database::query($sql), 'ASSOC'); + } }