diff --git a/main/admin/index.php b/main/admin/index.php
index 4398b0e02b..e4860c87ec 100644
--- a/main/admin/index.php
+++ b/main/admin/index.php
@@ -147,6 +147,11 @@ if (api_is_platform_admin()) {
'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 @@ if (api_is_platform_admin()) {
'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 0000000000..0ff0ea5330
--- /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 410e628adb..5127b58f64 100755
--- a/main/inc/ajax/user_manager.ajax.php
+++ b/main/inc/ajax/user_manager.ajax.php
@@ -463,6 +463,86 @@ switch ($action) {
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 0504323f5e..0c4aadee29 100755
--- a/main/inc/lib/usermanager.lib.php
+++ b/main/inc/lib/usermanager.lib.php
@@ -8261,4 +8261,52 @@ SQL;
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');
+ }
}