From 5ccab235ef2a32c2795c6dab60eeed3b7edcc716 Mon Sep 17 00:00:00 2001 From: Jan <96944229+modelrailroader@users.noreply.github.com> Date: Wed, 1 May 2024 18:50:56 +0200 Subject: [PATCH] refactor: move user management to twig (#2791) --- phpmyfaq/admin/assets/src/api/user.js | 21 + phpmyfaq/admin/assets/src/user/user-list.js | 67 +- phpmyfaq/admin/assets/src/user/users.js | 187 +++- phpmyfaq/admin/user.php | 928 +++--------------- .../assets/templates/admin/user/users.twig | 511 ++++++++++ phpmyfaq/src/admin-routes.php | 8 + .../Administration/UserController.php | 124 ++- phpmyfaq/translations/language_de.php | 3 + phpmyfaq/translations/language_en.php | 3 + 9 files changed, 959 insertions(+), 893 deletions(-) create mode 100644 phpmyfaq/assets/templates/admin/user/users.twig diff --git a/phpmyfaq/admin/assets/src/api/user.js b/phpmyfaq/admin/assets/src/api/user.js index eec555d01d..9c3e7b62d6 100644 --- a/phpmyfaq/admin/assets/src/api/user.js +++ b/phpmyfaq/admin/assets/src/api/user.js @@ -126,3 +126,24 @@ export const postUserData = async (url = '', data = {}) => { throw error; } }; + +export const deleteUser = async (userId, csrfToken) => { + try { + return await fetch('./api/user/delete', { + method: 'DELETE', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/json', + }, + redirect: 'follow', + referrerPolicy: 'no-referrer', + body: JSON.stringify({ + csrfToken: csrfToken, + userId: userId + }), + }); + } catch (error) { + console.error('Error posting user data:', error); + throw error; + } +}; diff --git a/phpmyfaq/admin/assets/src/user/user-list.js b/phpmyfaq/admin/assets/src/user/user-list.js index 6dfca51550..9bc7e94c80 100644 --- a/phpmyfaq/admin/assets/src/user/user-list.js +++ b/phpmyfaq/admin/assets/src/user/user-list.js @@ -16,7 +16,9 @@ */ import { addElement } from '../../../../assets/src/utils'; -import { pushNotification } from '../utils'; +import { pushErrorNotification, pushNotification } from '../utils'; +import { deleteUser } from '../api'; +import { Modal } from 'bootstrap'; const activateUser = async (userId, csrfToken) => { try { @@ -51,40 +53,6 @@ const activateUser = async (userId, csrfToken) => { } }; -const deleteUser = async (userId, csrfToken) => { - const message = document.getElementById('pmf-user-message'); - - try { - const response = await fetch('./api/user/delete', { - method: 'DELETE', - headers: { - Accept: 'application/json, text/plain, */*', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - csrfToken: csrfToken, - userId: userId, - }), - }); - - if (response.ok) { - const responseData = await response.json(); - const row = document.querySelector(`.row_user_id_${userId}`); - row.addEventListener('click', () => (row.style.opacity = '0')); - row.addEventListener('transitionend', () => row.remove()); - pushNotification(responseData); - } else { - throw new Error('Network response was not ok: ', { cause: { response } }); - } - } catch (error) { - const errorMessage = await error.cause.response.json(); - message.insertAdjacentElement( - 'afterend', - addElement('div', { classList: 'alert alert-danger', innerText: errorMessage }) - ); - } -}; - export const handleUserList = () => { const activateButtons = document.querySelectorAll('.btn-activate-user'); const deleteButtons = document.querySelectorAll('.btn-delete-user'); @@ -107,11 +75,32 @@ export const handleUserList = () => { button.addEventListener('click', (event) => { event.preventDefault(); - const csrfToken = event.target.getAttribute('data-csrf-token'); - const userId = event.target.getAttribute('data-user-id'); - - deleteUser(userId, csrfToken); + const deleteModal = new Modal(document.getElementById('pmf-modal-user-confirm-delete')); + deleteModal.show(); + document.getElementById('pmf-username-delete').innerText = button.getAttribute('data-username'); + document.getElementById('pmf-user-id-delete').value = button.getAttribute('data-user-id'); + document.getElementById('source_page').value = 'user-list'; }); }); + + const deleteUserConfirm = document.getElementById('pmf-delete-user-yes'); + deleteUserConfirm.addEventListener('click', async (event) => { + event.preventDefault(); + const source = document.getElementById('source_page'); + if (source.value === 'user-list') { + const userId = document.getElementById('pmf-user-id-delete').value; + const csrfToken = document.getElementById('csrf-token-delete-user').value; + const response = await deleteUser(userId, csrfToken); + const json = await response.json(); + if (json.success) { + pushNotification(json.success); + const row = document.getElementById('row_user_id_' + userId); + row.remove(); + } + if (json.error) { + pushErrorNotification(json.error); + } + } + }); } }; diff --git a/phpmyfaq/admin/assets/src/user/users.js b/phpmyfaq/admin/assets/src/user/users.js index 6cc75a177f..5c13d2a368 100644 --- a/phpmyfaq/admin/assets/src/user/users.js +++ b/phpmyfaq/admin/assets/src/user/users.js @@ -16,9 +16,9 @@ */ import { Modal } from 'bootstrap'; -import { fetchAllUsers, fetchUserData, fetchUserRights, postUserData } from '../api'; +import { fetchAllUsers, fetchUserData, fetchUserRights, deleteUser, postUserData } from '../api'; import { addElement, capitalize } from '../../../../assets/src/utils'; -import { pushNotification } from '../utils'; +import { pushErrorNotification, pushNotification } from '../utils'; /** * Updates the current loaded user @@ -57,6 +57,13 @@ const setUserData = async (userId) => { twoFactorEnabled.setAttribute('checked', 'checked'); twoFactorEnabled.removeAttribute('disabled'); } + + if (userData.status !== 'protected') { + const deleteUser = document.getElementById('pmf-delete-user'); + deleteUser.classList.remove('disabled'); + } + const saveUser = document.getElementById('pmf-user-save'); + saveUser.classList.remove('disabled'); }; const setUserRights = async (userId) => { @@ -69,10 +76,34 @@ const setUserRights = async (userId) => { document.getElementById('rights_user_id').value = userId; }; +const clearUserForm = async () => { + updateInput('current_user_id', ''); + updateInput('pmf-user-list-autocomplete', ''); + updateInput('last_modified', ''); + updateInput('update_user_id', ''); + updateInput('modal_user_id', ''); + updateInput('auth_source', ''); + updateInput('user_status', ''); + updateInput('display_name', ''); + updateInput('email', ''); + updateInput('overwrite_twofactor', ''); + + document.querySelectorAll('.permission').forEach((item) => { + if (item.checked) { + item.removeAttribute('checked'); + } + }); + + document.getElementById('pmf-user-save').classList.add('disabled'); + document.getElementById('pmf-delete-user').classList.add('disabled'); +}; + const updateInput = (id, value) => { const input = document.getElementById(id); - input.value = value; - input.removeAttribute('disabled'); + if (input) { + input.value = value; + input.removeAttribute('disabled'); + } }; export const handleUsers = async () => { @@ -144,51 +175,26 @@ export const handleUsers = async () => { if (response.ok) { return response.json(); } + if (response.status === 400) { + const json = await response.json(); + json.forEach((item) => { + pushErrorNotification(item); + }); + } throw new Error('Network response was not ok: ', { cause: { response } }); }) .then((response) => { modal.style.display = 'none'; modal.classList.remove('show'); modalBackdrop[0].parentNode.removeChild(modalBackdrop[0]); - - const tableBody = document.querySelector('#pmf-admin-user-table tbody'); - const row = addElement('tr', { id: `row_user_id_${response.id}` }, [ - addElement('td', { innerText: response.realName }), - addElement('td', {}, [addElement('a', { href: 'mailto:' + response.email, innerText: response.email })]), - addElement('td', { innerText: response.userName }), - addElement('td', { className: 'text-center' }, [ - addElement('i', { - className: response.status ? 'bi bi-check-circle-o text-success' : 'bi bi-ban text-danger', - }), - ]), - addElement('td', { className: 'text-center' }, [ - addElement('i', { className: response.isSuperAdmin ? 'bi bi-user-secret' : 'bi bi-user-times' }), - ]), - addElement('td', { className: 'text-center' }, [ - addElement('i', { className: response.isVisible ? 'bi bi-user' : 'bi bi-user-o' }), - ]), - addElement('td', {}, [ - addElement('a', { className: 'btn', href: `?action=user&user_id=${response.id}` }, [ - addElement('i', { className: 'bi bi-pencil text-info' }), - addElement('span', { innerText: ' ' + response.editTranslationString }), - ]), - ]), - addElement('td', {}), - addElement('td', {}), - ]); - tableBody.appendChild(row); pushNotification(response.success); + setTimeout(() => { + location.reload(); + }, 1500); }) .catch(async (error) => { - const errors = await error.cause.response.json(); - let errorMessage = ''; - - errors.forEach((error) => { - errorMessage += `${error}
`; - }); - - addUserError.classList.remove('d-none'); - addUserError.innerHTML = errorMessage; + console.error('Error adding user: ' + error); + throw error; }); }); } @@ -204,7 +210,7 @@ export const handleUsers = async () => { const replacer = (key, value) => (value === null ? '' : value); const header = Object.keys(userData[0]); let csv = userData.map((row) => - header.map((fieldName) => JSON.stringify(row[fieldName], replacer)).join(',') + header.map((fieldName) => JSON.stringify(row[fieldName], replacer)).join(','), ); csv.unshift(header.join(',')); csv = csv.join('\r\n'); @@ -216,7 +222,7 @@ export const handleUsers = async () => { hiddenElement.setAttribute('target', '_blank'); hiddenElement.setAttribute( 'download', - 'phpmyfaq-users-' + new Date().toISOString().substring(0, 10) + '.csv' + 'phpmyfaq-users-' + new Date().toISOString().substring(0, 10) + '.csv', ); hiddenElement.click(); }) @@ -263,7 +269,7 @@ export const handleUsers = async () => { .then((response) => { message.insertAdjacentElement( 'afterend', - addElement('div', { classList: 'alert alert-success', innerText: response.success }) + addElement('div', { classList: 'alert alert-success', innerText: response.success }), ); modal.hide(); }) @@ -272,9 +278,102 @@ export const handleUsers = async () => { console.error(errorMessage.error); message.insertAdjacentElement( 'afterend', - addElement('div', { classList: 'alert alert-danger', innerText: errorMessage.error }) + addElement('div', { classList: 'alert alert-danger', innerText: errorMessage.error }), ); }); }); } + + // Delete user + const deleteUserButton = document.getElementById('pmf-delete-user'); + const deleteUser_yes = document.getElementById('pmf-delete-user-yes'); + + if (deleteUserButton) { + deleteUserButton.addEventListener('click', (event) => { + event.preventDefault(); + const modalDeleteConfirmation = new Modal(document.getElementById('pmf-modal-user-confirm-delete')); + modalDeleteConfirmation.show(); + const username = document.getElementById('pmf-username-delete'); + const userid = document.getElementById('pmf-user-id-delete'); + username.innerText = document.getElementById('display_name').value; + userid.value = document.getElementById('current_user_id').value; + document.getElementById('source_page').value = 'users'; + }); + deleteUser_yes.addEventListener('click', async (event) => { + event.preventDefault(); + const source = document.getElementById('source_page'); + if (source.value === 'users') { + const userId = document.getElementById('pmf-user-id-delete').value; + const csrfToken = document.getElementById('csrf-token-delete-user').value; + const response = await deleteUser(userId, csrfToken); + const json = await response.json(); + if (json.success) { + pushNotification(json.success); + await clearUserForm(); + } + if (json.error) { + pushErrorNotification(json.error); + } + } + }); + } + + // Edit user + const editUserButton = document.getElementById('pmf-user-save'); + if (editUserButton) { + editUserButton.addEventListener('click', async (event) => { + event.preventDefault(); + const userId = document.getElementById('update_user_id').value; + let userData = { + csrfToken: document.getElementById('pmf-csrf-token').value, + display_name: document.getElementById('display_name').value, + email: document.getElementById('email').value, + last_modified: document.getElementById('last_modified').value, + user_status: document.getElementById('user_status').value, + is_superadmin: document.getElementById('is_superadmin').checked, + overwrite_twofactor: document.getElementById('overwrite_twofactor').checked, + userId: userId + }; + + console.log(userData); + + const response = await postUserData('./api/user/edit', userData); + const json = await response.json(); + if (json.success) { + pushNotification(json.success); + } + if (json.error) { + pushErrorNotification(json.error); + } + await updateUser(userId); + }); + } + + // Update user rights + document.querySelectorAll('#pmf-user-rights-save').forEach((item) => { + item.addEventListener('click', async (event) => { + event.preventDefault(); + let rightData = []; + document.querySelectorAll('.permission').forEach(async (checkbox) => { + if (checkbox.checked) { + rightData.push(checkbox.value); + } + }); + const userId = document.getElementById('rights_user_id').value + let data = { + csrfToken: document.getElementById('pmf-csrf-token-rights').value, + userId: userId, + userRights: rightData + } + const response = await postUserData('./api/user/update-rights', data); + const json = await response.json(); + if (json.success) { + pushNotification(json.success); + } + if (json.error) { + pushErrorNotification(json.error); + } + await updateUser(userId); + }); + }); }; diff --git a/phpmyfaq/admin/user.php b/phpmyfaq/admin/user.php index 79f23da2ab..ebb4847d3d 100755 --- a/phpmyfaq/admin/user.php +++ b/phpmyfaq/admin/user.php @@ -26,9 +26,12 @@ use phpMyFAQ\Permission; use phpMyFAQ\Session\Token; use phpMyFAQ\Strings; +use phpMyFAQ\Template\PermissionTranslationTwigExtension; +use phpMyFAQ\Template\TwigWrapper; use phpMyFAQ\Translation; use phpMyFAQ\User; use phpMyFAQ\User\CurrentUser; +use Twig\Extension\DebugExtension; if (!defined('IS_VALID_PHPMYFAQ')) { http_response_code(400); @@ -36,807 +39,160 @@ } if ( - $user->perm->hasPermission($user->getUserId(), PermissionType::USER_EDIT->value) || - $user->perm->hasPermission($user->getUserId(), PermissionType::USER_DELETE->value) || - $user->perm->hasPermission($user->getUserId(), PermissionType::USER_ADD->value) + !$user->perm->hasPermission($user->getUserId(), PermissionType::USER_EDIT->value) || + !$user->perm->hasPermission($user->getUserId(), PermissionType::USER_DELETE->value) || + !$user->perm->hasPermission($user->getUserId(), PermissionType::USER_ADD->value) ) { - $userId = Filter::filterInput(INPUT_GET, 'user_id', FILTER_VALIDATE_INT); - - // set some parameters - $selectSize = 10; - $defaultUserAction = 'list'; - $defaultUserStatus = 'active'; - $userActionList = [ - 'update_rights', - 'update_data', - 'delete_confirm', - 'delete', - 'addsave', - 'list', - 'listallusers' - ]; - - // what shall we do? - // actions defined by url: user_action= - $userAction = Filter::filterInput(INPUT_GET, 'user_action', FILTER_SANITIZE_SPECIAL_CHARS, $defaultUserAction); - - $currentUser = new CurrentUser($faqConfig); - - // actions defined by submit button - if (isset($_POST['user_action_deleteConfirm'])) { - $userAction = 'delete_confirm'; - } - if (isset($_POST['cancel'])) { - $userAction = $defaultUserAction; - } - - // update user rights - if ( - $userAction == 'update_rights' && - $user->perm->hasPermission($user->getUserId(), PermissionType::USER_EDIT->value) - ) { - $message = ''; - $userAction = $defaultUserAction; - $userId = Filter::filterInput(INPUT_POST, 'user_id', FILTER_VALIDATE_INT, 0); - $csrfOkay = true; - $csrfToken = Filter::filterInput(INPUT_POST, 'pmf-csrf-token', FILTER_SANITIZE_SPECIAL_CHARS); - if (!Token::getInstance()->verifyToken('update-user-rights', $csrfToken)) { - $csrfOkay = false; - } - - if (0 === (int)$userId || !$csrfOkay) { - $message .= Alert::danger('ad_user_error_noId'); - } else { - $user = new User($faqConfig); - $perm = $user->perm; - // @todo: Add Filter::filterInput[] - $userRights = $_POST['user_rights'] ?? []; - if (!$perm->refuseAllUserRights($userId)) { - $message .= Alert::danger('ad_msg_mysqlerr'); - } - foreach ($userRights as $rightId) { - $perm->grantUserRight($userId, $rightId); - } - - $idUser = $user->getUserById($userId, true); - // Terminate session in case of different permissions after the update - $user->terminateSessionId(); - $message .= sprintf( - '

%s %s %s

', - Translation::get('ad_msg_savedsuc_1'), - Strings::htmlentities($user->getLogin(), ENT_QUOTES), - Translation::get('ad_msg_savedsuc_2') - ); - $user = new CurrentUser($faqConfig); - } - } - - // update user data - if ( - $userAction == 'update_data' && - $user->perm->hasPermission($user->getUserId(), PermissionType::USER_EDIT->value) - ) { - $message = ''; - $userAction = $defaultUserAction; - $userId = Filter::filterInput(INPUT_POST, 'user_id', FILTER_VALIDATE_INT, 0); - if ($userId === 0) { - $message .= Alert::danger('ad_user_error_noId'); - } else { - $userData = []; - $userData['display_name'] = Filter::filterInput(INPUT_POST, 'display_name', FILTER_SANITIZE_SPECIAL_CHARS); - $userData['email'] = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); - $userData['last_modified'] = Filter::filterInput(INPUT_POST, 'last_modified', FILTER_SANITIZE_SPECIAL_CHARS); - $userStatus = Filter::filterInput(INPUT_POST, 'user_status', FILTER_SANITIZE_SPECIAL_CHARS, $defaultUserStatus); - $isSuperAdmin = Filter::filterInput(INPUT_POST, 'is_superadmin', FILTER_SANITIZE_SPECIAL_CHARS); - $isSuperAdmin = $isSuperAdmin === 'on'; - $deleteTwofactor = Filter::filterInput(INPUT_POST, 'overwrite_twofactor', FILTER_SANITIZE_SPECIAL_CHARS); - $deleteTwofactor = $deleteTwofactor === 'on'; - - $user = new User($faqConfig); - $user->getUserById($userId, true); - - $stats = $user->getStatus(); - - // reset two-factor authentication if required - if ($deleteTwofactor) { - $user->setUserData(['secret' => '', 'twofactor_enabled' => 0]); - } - - // set new password and sent email if a user is switched to active - if ($stats == 'blocked' && $userStatus == 'active') { - if (!$user->activateUser()) { - $userStatus = 'invalid_status'; - } - } - - // Set super-admin flag - $user->setSuperAdmin($isSuperAdmin); + require __DIR__ . '/no-permission.php'; + exit(); +} - if ( - !$user->userdata->set(array_keys($userData), array_values($userData)) || !$user->setStatus( - $userStatus - ) - ) { - $message .= Alert::danger('ad_msg_mysqlerr'); - } else { - $message .= sprintf( - '

%s %s %s

', - Translation::get('ad_msg_savedsuc_1'), - Strings::htmlentities($user->getLogin(), ENT_QUOTES), - Translation::get('ad_msg_savedsuc_2') - ); - } - } - } +$templateVars = []; - // delete user confirmation - if ( - $userAction == 'delete_confirm' && - $user->perm->hasPermission($user->getUserId(), PermissionType::USER_DELETE->value) - ) { - $message = ''; - $user = new CurrentUser($faqConfig); +$userId = Filter::filterInput(INPUT_GET, 'user_id', FILTER_VALIDATE_INT); - $userId = Filter::filterInput(INPUT_GET, 'user_delete_id', FILTER_VALIDATE_INT, 0); - if ($userId == 0) { - $message .= Alert::danger('ad_user_error_noId'); - $userAction = $defaultUserAction; - } else { - $user->getUserById($userId, true); - // account is protected - if ($user->getStatus() == 'protected' || $userId == 1) { - $message .= Alert::danger('ad_user_error_protectedAccount'); - $userAction = $defaultUserAction; - } else { - ?> +// set some parameters +$selectSize = 10; +$defaultUserAction = 'list'; +$userActionList = [ + 'list', + 'listallusers' +]; -
-

- - - getLogin(), ENT_QUOTES) ?> -

-
+// what shall we do? +// actions defined by url: user_action= +$userAction = Filter::filterInput(INPUT_GET, 'user_action', FILTER_SANITIZE_SPECIAL_CHARS, $defaultUserAction); +$currentUser = new CurrentUser($faqConfig); -

- -

-
- - getTokenInput('delete-user') ?> -

- - - - -

-
- perm->hasPermission($user->getUserId(), PermissionType::USER_EDIT->value)) { + require __DIR__ . '/no-permission.php'; + exit(); } + $allUsers = $user->getAllUsers(false); + $numUsers = is_countable($allUsers) ? count($allUsers) : 0; + $page = Filter::filterInput(INPUT_GET, 'page', FILTER_VALIDATE_INT, 0); + $perPage = 10; + $numPages = ceil($numUsers / $perPage); + $lastPage = $page * $perPage; + $firstPage = $lastPage - $perPage; + + $baseUrl = sprintf( + '%sadmin/?action=user&user_action=listallusers&page=%d', + $faqConfig->getDefaultUrl(), + $page + ); + + // Pagination options + $options = [ + 'baseUrl' => $baseUrl, + 'total' => $numUsers, + 'perPage' => $perPage, + 'pageParamName' => 'page', + ]; + $pagination = new Pagination($options); - // delete user - if ($userAction == 'delete' && $user->perm->hasPermission($user->getUserId(), PermissionType::USER_DELETE->value)) { - $message = ''; - $user = new User($faqConfig); - $userId = Filter::filterInput(INPUT_POST, 'user_id', FILTER_VALIDATE_INT, 0); - $csrfOkay = true; - $csrfToken = Filter::filterInput(INPUT_POST, 'pmf-csrf-token', FILTER_SANITIZE_SPECIAL_CHARS); - $userAction = $defaultUserAction; + $counter = $displayedCounter = 0; + $users = []; + foreach ($allUsers as $listedUserId) { + $user->getUserById($listedUserId, true); + $tempUser = []; - if (!Token::getInstance()->verifyToken('delete-user', $csrfToken)) { - $csrfOkay = false; + if ($displayedCounter >= $perPage) { + continue; } - - if (0 === (int)$userId || !$csrfOkay) { - $message .= Alert::danger('ad_user_error_noId'); - } else { - if (!$user->getUserById($userId, true)) { - $message .= Alert::danger('ad_user_error_noId'); - } - if (!$user->deleteUser()) { - $message .= Alert::danger('ad_user_error_delete'); - } else { - // Move the category ownership to admin (id == 1) - $oCat = new Category($faqConfig, [], false); - $oCat->setUser($currentAdminUser); - $oCat->setGroups($currentAdminGroups); - $oCat->moveOwnership((int)$userId, 1); - - // Remove the user from groups - if ('basic' !== $faqConfig->get('security.permLevel')) { - $oPerm = Permission::selectPerm('medium', $faqConfig); - $oPerm->removeFromAllGroups($userId); - } - - $message .= Alert::success('ad_user_deleted'); - } - $userError = $user->error(); - if ($userError != '') { - $message .= sprintf('

%s

', $userError); - } + ++$counter; + if ($counter <= $firstPage) { + continue; } - } - - if (!isset($message)) { - $message = ''; - } - - // show a list of users - if ($userAction === 'list') { ?> -
-

- - -

-
-
- perm->hasPermission($user->getUserId(), PermissionType::USER_ADD->value)) : ?> - - - perm->hasPermission($user->getUserId(), PermissionType::USER_EDIT->value)) : ?> - - - - -
-
-
- -
- -
-
-
- -
-
- -
-
-
- - -
-
-
-
-
-
- -
- -
-
-
- -
-
-
- - - getTokenInput('update-user-data') ?> - -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
-
-
- - -
-
-
- -
-
- - - -
-
- -
-
-
- - -
-
-
- -
- -
-
-
- -
-
- - getTokenInput('update-user-rights') ?> - -
-
-
- -
-
- -
-
-
-
- -
- perm->getAllRightsData() as $right) : ?> -
- - -
- -
- -
-
-
-
- - perm->hasPermission($user->getUserId(), PermissionType::USER_EDIT->value) - ) { - $allUsers = $user->getAllUsers(false); - $numUsers = is_countable($allUsers) ? count($allUsers) : 0; - $page = Filter::filterInput(INPUT_GET, 'page', FILTER_VALIDATE_INT, 0); - $perPage = 10; - $numPages = ceil($numUsers / $perPage); - $lastPage = $page * $perPage; - $firstPage = $lastPage - $perPage; - - $baseUrl = sprintf( - '%sadmin/?action=user&user_action=listallusers&page=%d', - $faqConfig->getDefaultUrl(), - $page - ); - - // Pagination options - $options = [ - 'baseUrl' => $baseUrl, - 'total' => $numUsers, - 'perPage' => $perPage, - 'pageParamName' => 'page', + ++$displayedCounter; + + $tempUser = [ + 'display_name' => Strings::htmlentities($user->getUserData('display_name')), + 'id' => $user->getUserId(), + 'email' => Strings::htmlentities($user->getUserData('email')), + 'status' => $user->getStatus(), + 'isSuperAdmin' => $user->isSuperAdmin(), + 'isVisible' => $user->getUserData('is_visible'), + 'login' => Strings::htmlentities($user->getLogin()) ]; - $pagination = new Pagination($options); - ?> - -
-

- - -

-
-
- perm->hasPermission($user->getUserId(), PermissionType::USER_ADD->value)) : ?> - - - -
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - getUserById($listedUserId, true); - - if ($displayedCounter >= $perPage) { - continue; - } - ++$counter; - if ($counter <= $firstPage) { - continue; - } - ++$displayedCounter; - - ?> - - - - - - - - - - - - - -
Actions
render() ?>
getUserData('display_name')) ?> - - getUserData('email')) ?> - - getLogin()) ?> - - - - - - getUserData('email')) ?> - - - - - - getStatus() === 'blocked') : ?> - - - getStatus() !== 'protected' && - $currentUser->perm->hasPermission( - $currentUser->getUserId(), - PermissionType::USER_DELETE->value - ) - ) { - $csrfToken = Token::getInstance()->getTokenString('delete-user'); - ?> - - -
- - - - - - - - - $perPage, + 'numUsers' => $numUsers, + 'pagination' => $pagination->render(), + 'users' => $users, + 'userIsSuperAdmin' => $user->isSuperAdmin() + ]; } + +$templateVars = [ + ...$templateVars, + 'userAction' => $userAction, + 'ad_user' => Translation::get('ad_user'), + 'permissionAddUser' => $currentUser->perm->hasPermission($user->getUserId(), PermissionType::USER_ADD->value), + 'ad_user_add' => Translation::get('ad_user_add'), + 'permissionEditUser' => $currentUser->perm->hasPermission($user->getUserId(), PermissionType::USER_EDIT->value), + 'list_all_users' => Translation::get('list_all_users'), + 'userId' => $userId, + 'msgSearch' => Translation::get('msgSearch'), + 'ad_auth_user' => Translation::get('ad_auth_user'), + 'ad_user_profou' => Translation::get('ad_user_profou'), + 'csrfToken_updateUserData' => Token::getInstance()->getTokenString('update-user-data'), + 'msgAuthenticationSource' => Translation::get('msgAuthenticationSource'), + 'ad_user_status' => Translation::get('ad_user_status'), + 'ad_user_active' => Translation::get('ad_user_active'), + 'ad_user_blocked' => Translation::get('ad_user_blocked'), + 'ad_user_protected' => Translation::get('ad_user_protected'), + 'ad_user_realname' => Translation::get('ad_user_realname'), + 'ad_entry_email' => Translation::get('ad_entry_email'), + 'ad_user_is_superadmin' => Translation::get('ad_user_is_superadmin'), + 'ad_user_overwrite_passwd' => Translation::get('ad_user_overwrite_passwd'), + 'ad_user_overwrite_twofactor' => Translation::get('ad_user_overwrite_twofactor'), + 'ad_user_delete' => Translation::get('ad_user_delete'), + 'ad_gen_save' => Translation::get('ad_gen_save'), + 'csrfToken_updateUserRights' => Token::getInstance()->getTokenString('update-user-rights'), + 'ad_user_rights' => Translation::get('ad_user_rights'), + 'ad_user_checkall' => Translation::get('ad_user_checkall'), + 'ad_user_uncheckall' => Translation::get('ad_user_uncheckall'), + 'userRights' => $user->perm->getAllRightsData(), + 'msgExportUsersAsCSV' => Translation::get('msgExportUsersAsCSV'), + 'msgNewContentName' => Translation::get('msgNewContentName'), + 'msgNewContentMail' => Translation::get('msgNewContentMail'), + 'ad_user_is_visible' => Translation::get('ad_user_is_visible'), + 'ad_user_edit' => Translation::get('ad_user_edit'), + 'csrfToken_activateUser' => Token::getInstance()->getTokenString('activate-user'), + 'ad_news_set_active' => Translation::get('ad_news_set_active'), + 'permissionDeleteUser' => + $currentUser->perm->hasPermission($user->getUserId(), PermissionType::USER_DELETE->value), + 'csrfToken_deleteUser' => Token::getInstance()->getTokenString('delete-user'), + 'ad_adus_adduser' => Translation::get('ad_adus_adduser'), + 'csrfToken_addUser' => Token::getInstance()->getTokenString('add-user'), + 'ad_adus_name' => Translation::get('ad_adus_name'), + 'ad_add_user_change_password' => Translation::get('ad_add_user_change_password'), + 'ad_adus_password' => Translation::get('ad_adus_password'), + 'ad_passwd_con' => Translation::get('ad_passwd_con'), + 'ad_gen_cancel' => Translation::get('ad_gen_cancel'), + 'ad_menu_passwd' => Translation::get('ad_menu_passwd'), + 'csrfToken_overwritePassword' => Token::getInstance()->getTokenString('overwrite-password'), + 'ad_passwd_new' => Translation::get('ad_passwd_new'), + 'msgWarning' => Translation::get('msgWarning'), + 'ad_gen_yes' => Translation::get('ad_gen_yes'), + 'ad_gen_no' => Translation::get('ad_gen_no'), + 'ad_user_deleteUser' => Translation::get('ad_user_deleteUser'), + 'msgUserList' => Translation::get('msgUserList') +]; + +$twig = new TwigWrapper(PMF_ROOT_DIR . '/assets/templates'); +$twig->addExtension(new DebugExtension()); +$twig->addExtension(new PermissionTranslationTwigExtension()); +$template = $twig->loadTemplate('./admin/user/users.twig'); + +echo $template->render($templateVars); diff --git a/phpmyfaq/assets/templates/admin/user/users.twig b/phpmyfaq/assets/templates/admin/user/users.twig new file mode 100644 index 0000000000..8444263f6e --- /dev/null +++ b/phpmyfaq/assets/templates/admin/user/users.twig @@ -0,0 +1,511 @@ +{% if userAction == 'list' %} +
+

+ + {{ ad_user }} +

+
+
+ {% if permissionAddUser == true %} + + {% endif %} + {% if permissionEditUser == true %} + + {{ list_all_users }} + + {% endif %} +
+
+
+ +
+
+
+ +
+
+ {{ msgSearch }} +
+
+
+ + +
+
+
+
+
+
+ +
+ +
+
+
+ {{ ad_user_profou }} +
+
+ + + + +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ + +
+
+
+ + + +
+
+
+ + +
+
+
+ +
+ +
+
+ +
+ + + +
+
+
+ {{ ad_user_rights }} +
+
+ +
+
+
+
+ +
+ {% for right in userRights %} +
+ + +
+ {% endfor %} +
+ +
+
+
+{% endif %} +{% if userAction == 'listallusers' and permissionEditUser == true %} +
+

+ + {{ msgUserList }} +

+
+
+ + {{ ad_user }} + + {% if permissionAddUser == true %} + + {% endif %} + +
+
+
+ + + + + + + + + + + + + + {% if perPage < numUsers %} + + + + + + {% endif %} + + {% for user in users %} + + + + + + + + + + + + {% endfor %} + +
{{ msgNewContentName }}{{ msgNewContentMail }}{{ ad_auth_user }}{{ ad_user_status }}{{ ad_user_is_superadmin }}{{ ad_user_is_visible }}Actions
{{ pagination|raw }}
{{ user.display_name|raw }} + + {{ user.email|raw }} + + {{ user.login|raw }} + + + + + + {{ ad_user_edit }} + + {% if user.status == 'blocked' %} + + {% endif %} + {% if user.status != 'protected' and permissionDeleteUser == true %} + + {% endif %} +
+{% endif %} + + + + + + + +{% if permissionDeleteUser == true %} + +