diff --git a/nginx.conf b/nginx.conf index e5e3fd512f..67e09e6b85 100644 --- a/nginx.conf +++ b/nginx.conf @@ -158,6 +158,13 @@ server { rewrite admin/api/group/members /admin/api/index.php last; rewrite admin/api/group/permissions /admin/api/index.php last; rewrite admin/api/search/term /admin/api/index.php last; + rewrite admin/api/user/users /admin/api/index.php last; + rewrite admin/api/user/activate /admin/api/index.php last; + rewrite admin/api/user/add /admin/api/index.php last; + rewrite admin/api/user/data /admin/api/index.php last; + rewrite admin/api/user/delete /admin/api/index.php last; + rewrite admin/api/user/permissions /admin/api/index.php last; + rewrite admin/api/user/overwrite-password /admin/api/index.php last; rewrite admin/api/health-check /admin/api/index.php last; rewrite admin/api/updates /admin/api/index.php last; rewrite admin/api/update-check /admin/api/index.php last; diff --git a/phpmyfaq/.htaccess b/phpmyfaq/.htaccess index 6ee8bda445..7d0573163b 100644 --- a/phpmyfaq/.htaccess +++ b/phpmyfaq/.htaccess @@ -169,6 +169,13 @@ RewriteRule admin/api/group/members admin/api/index.php RewriteRule admin/api/group/permissions admin/api/index.php RewriteRule admin/api/group/users admin/api/index.php RewriteRule admin/api/search/term admin/api/index.php +RewriteRule admin/api/user/users admin/api/index.php +RewriteRule admin/api/user/activate admin/api/index.php +RewriteRule admin/api/user/add admin/api/index.php +RewriteRule admin/api/user/data admin/api/index.php +RewriteRule admin/api/user/delete admin/api/index.php +RewriteRule admin/api/user/permissions admin/api/index.php +RewriteRule admin/api/user/overwrite-password admin/api/index.php RewriteRule admin/api/health-check admin/api/index.php RewriteRule admin/api/versions admin/api/index.php RewriteRule admin/api/update-check admin/api/index.php diff --git a/phpmyfaq/admin/api/user.php b/phpmyfaq/admin/api/user.php deleted file mode 100644 index f66ca5c519..0000000000 --- a/phpmyfaq/admin/api/user.php +++ /dev/null @@ -1,302 +0,0 @@ - - * @copyright 2009-2023 phpMyFAQ Team - * @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0 - * @link https://www.phpmyfaq.de - * @since 2009-04-04 - */ - -use phpMyFAQ\Administration\Report; -use phpMyFAQ\Auth; -use phpMyFAQ\Category; -use phpMyFAQ\Component\Alert; -use phpMyFAQ\Core\Exception; -use phpMyFAQ\Filter; -use phpMyFAQ\Helper\MailHelper; -use phpMyFAQ\Permission; -use phpMyFAQ\Session\Token; -use phpMyFAQ\Strings; -use phpMyFAQ\Translation; -use phpMyFAQ\User; -use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Mailer\Exception\TransportExceptionInterface; - -if (!defined('IS_VALID_PHPMYFAQ')) { - http_response_code(400); - exit(); -} - -// -// Create Request & Response -// -$response = new JsonResponse(); -$request = Request::createFromGlobals(); - -$ajaxAction = Filter::filterVar($request->query->get('ajaxaction'), FILTER_SANITIZE_SPECIAL_CHARS); -$userId = Filter::filterInput(INPUT_GET, 'user_id', FILTER_VALIDATE_INT); -$userSearch = Filter::filterInput(INPUT_GET, 'q', FILTER_SANITIZE_SPECIAL_CHARS); -$csrfToken = Filter::filterInput(INPUT_GET, 'csrf', FILTER_SANITIZE_SPECIAL_CHARS); - -if ( - $user->perm->hasPermission($user->getUserId(), 'add_user') || - $user->perm->hasPermission($user->getUserId(), 'edit_user') || - $user->perm->hasPermission($user->getUserId(), 'delete_user') -) { - $user = new User($faqConfig); - - switch ($ajaxAction) { - case 'get_user_list': - $allUsers = []; - foreach ($user->searchUsers($userSearch) as $singleUser) { - $users = new stdClass(); - $users->label = $singleUser['login']; - $users->value = (int)$singleUser['user_id']; - $allUsers[] = $users; - } - $response->setStatusCode(Response::HTTP_OK); - $response->setData($allUsers); - $response->send(); - break; - - case 'get_user_data': - $user->getUserById($userId, true); - $userdata = $user->userdata->get('*'); - if (is_array($userdata)) { - $userdata['status'] = $user->getStatus(); - $userdata['login'] = Strings::htmlentities($user->getLogin(), ENT_COMPAT); - $userdata['display_name'] = Strings::htmlentities($userdata['display_name'], ENT_COMPAT); - $userdata['is_superadmin'] = $user->isSuperAdmin(); - $userdata['auth_source'] = $user->getUserAuthSource(); - } else { - $userdata = []; - } - $response->setStatusCode(Response::HTTP_OK); - $response->setData($userdata); - $response->send(); - break; - - case 'get_all_user_data': - $allUsers = $user->getAllUsers(false); - $userData = []; - foreach ($allUsers as $userId) { - $user->getUserById($userId, true); - $userObject = new stdClass(); - $userObject->id = $user->getUserId(); - $userObject->status = $user->getStatus(); - $userObject->isSuperAdmin = $user->isSuperAdmin(); - $userObject->isVisible = $user->getUserData('is_visible'); - $userObject->displayName = Report::sanitize($user->getUserData('display_name')); - $userObject->userName = Report::sanitize($user->getLogin()); - $userObject->email = $user->getUserData('email'); - $userObject->authSource = $user->getUserAuthSource(); - $userData[] = $userObject; - } - $response->setStatusCode(Response::HTTP_OK); - $response->setData($userData); - $response->send(); - break; - - case 'get_user_rights': - $user->getUserById($userId, true); - $response->setData($user->perm->getUserRights($userId)); - $response->send(); - break; - - case 'activate_user': - $postData = json_decode(file_get_contents('php://input', true)); - if (!Token::getInstance()->verifyToken('activate-user', $postData->csrfToken)) { - $response->setStatusCode(Response::HTTP_UNAUTHORIZED); - $response->setData(['error' => Translation::get('err_NotAuth')]); - $response->send(); - exit(1); - } - - $userId = Filter::filterVar($postData->userId, FILTER_VALIDATE_INT); - - $user->getUserById($userId, true); - try { - if ($user->activateUser()) { - $response->setStatusCode(Response::HTTP_OK); - $response->setData(['success' => $user->getStatus()]); - } else { - $response->setStatusCode(Response::HTTP_BAD_REQUEST); - $response->setData(['error' => $user->getStatus()]); - } - } catch (TransportExceptionInterface $e) { - $response->setStatusCode(Response::HTTP_BAD_REQUEST); - $response->setData(['error' => $e->getMessage()]); - } - $response->send(); - break; - - case 'add_user': - if (!Token::getInstance()->verifyToken('add-user', $csrfToken)) { - $response->setStatusCode(Response::HTTP_UNAUTHORIZED); - $response->setData(['error' => Translation::get('err_NotAuth')]); - $response->send(); - exit(1); - } - - $errorMessage = []; - $successMessage = ''; - - $postData = json_decode(file_get_contents('php://input'), true); - - $userName = Filter::filterVar($postData['userName'], FILTER_SANITIZE_SPECIAL_CHARS); - $userRealName = Filter::filterVar($postData['realName'], FILTER_SANITIZE_SPECIAL_CHARS); - $userEmail = Filter::filterVar($postData['email'], FILTER_VALIDATE_EMAIL); - $automaticPassword = Filter::filterVar($postData['automaticPassword'], FILTER_VALIDATE_BOOLEAN); - $userPassword = Filter::filterVar($postData['password'], FILTER_SANITIZE_SPECIAL_CHARS); - $userPasswordConfirm = Filter::filterVar($postData['passwordConfirm'], FILTER_SANITIZE_SPECIAL_CHARS); - $userIsSuperAdmin = Filter::filterVar($postData['isSuperAdmin'], FILTER_VALIDATE_BOOLEAN); - - $newUser = new User($faqConfig); - - if (!$newUser->isValidLogin($userName)) { - $errorMessage[] = Translation::get('ad_user_error_loginInvalid'); - } - if ($newUser->getUserByLogin($userName)) { - $errorMessage[] = Translation::get('ad_adus_exerr'); - } - if ($userRealName === '') { - $errorMessage[] = Translation::get('ad_user_error_noRealName'); - } - if (is_null($userEmail)) { - $errorMessage[] = Translation::get('ad_user_error_noEmail'); - } - if (!$automaticPassword) { - if (strlen($userPassword) <= 7 || strlen($userPasswordConfirm) <= 7) { - $errorMessage[] = Translation::get('ad_passwd_fail'); - } - } else { - $userPassword = $newUser->createPassword(8, false); - } - - if (count($errorMessage) === 0) { - if (!$newUser->createUser($userName, $userPassword)) { - $errorMessage[] = $newUser->error(); - } else { - $newUser->userdata->set(['display_name', 'email', 'is_visible'], [$userRealName, $userEmail, 0]); - $newUser->setStatus('active'); - $newUser->setSuperAdmin((bool)$userIsSuperAdmin); - $mailHelper = new MailHelper($faqConfig); - try { - $mailHelper->sendMailToNewUser($newUser, $userPassword); - } catch (Exception $e) { - // @todo catch exception - } - $successMessage = [ - 'success' => Translation::get('ad_adus_suc'), - 'id' => $newUser->getUserId(), - 'status' => $newUser->getStatus(), - 'isSuperAdmin' => (bool)$userIsSuperAdmin, - 'isVisible' => (bool) $newUser->userdata->get('is_visible'), - 'realName' => $userRealName, - 'userName' => $userName, - 'email' => $userEmail, - 'editTranslationString' => Translation::get('ad_user_edit') - ]; - } - - $response->setStatusCode(Response::HTTP_OK); - $response->setData($successMessage); - $response->send(); - exit(1); - } - - $response->setStatusCode(Response::HTTP_BAD_REQUEST); - $response->setData($errorMessage); - $response->send(); - break; - - case 'delete_user': - $deleteData = json_decode(file_get_contents('php://input', true)); - - if (!Token::getInstance()->verifyToken('delete-user', $deleteData->csrfToken)) { - $response->setStatusCode(Response::HTTP_UNAUTHORIZED); - $response->setData(['error' => Translation::get('err_NotAuth')]); - $response->send(); - exit(1); - } - - $userId = Filter::filterVar($deleteData->userId, FILTER_VALIDATE_INT); - - $user->getUserById($userId, true); - if ($user->getStatus() == 'protected' || $userId == 1) { - $message = '

' . Translation::get('ad_user_error_protectedAccount') . '

'; - } else { - if (!$user->deleteUser()) { - $message = Translation::get('ad_user_error_delete'); - } else { - $category = new Category($faqConfig, [], false); - $category->moveOwnership((int) $userId, 1); - - // Remove the user from groups - if ('basic' !== $faqConfig->get('security.permLevel')) { - $permissions = Permission::selectPerm('medium', $faqConfig); - $permissions->removeFromAllGroups($userId); - } - - $message = Alert::success('ad_user_deleted'); - } - } - $response->setStatusCode(Response::HTTP_OK); - $response->setData($message); - $response->send(); - break; - - case 'overwrite_password': - $postData = json_decode(file_get_contents('php://input', true)); - - $userId = Filter::filterVar($postData->userId, FILTER_VALIDATE_INT); - $csrfToken = Filter::filterVar($postData->csrf, FILTER_SANITIZE_SPECIAL_CHARS); - $newPassword = Filter::filterVar($postData->newPassword, FILTER_SANITIZE_SPECIAL_CHARS); - $retypedPassword = Filter::filterVar($postData->passwordRepeat, FILTER_SANITIZE_SPECIAL_CHARS); - - if (!Token::getInstance()->verifyToken('overwrite-password', $csrfToken)) { - $response->setStatusCode(Response::HTTP_UNAUTHORIZED); - $response->setData(['error' => Translation::get('err_NotAuth')]); - $response->send(); - exit(1); - } - - if (strlen($newPassword) <= 7 || strlen($retypedPassword) <= 7) { - $response->setStatusCode(Response::HTTP_BAD_REQUEST); - $response->setData(['error' => Translation::get('ad_passwd_fail')]); - $response->send(); - exit(1); - } - - $user->getUserById($userId, true); - - $auth = new Auth($faqConfig); - $authSource = $auth->selectAuth($user->getAuthSource('name')); - $authSource->selectEncType($user->getAuthData('encType')); - - if ($newPassword === $retypedPassword) { - if (!$user->changePassword($newPassword)) { - $response->setStatusCode(Response::HTTP_BAD_REQUEST); - $response->setData(['error' => Translation::get('ad_passwd_fail')]); - $response->send(); - } - $response->setStatusCode(Response::HTTP_OK); - $response->setData(['success' => Translation::get('ad_passwdsuc')]); - } else { - $response->setStatusCode(Response::HTTP_BAD_REQUEST); - $response->setData(['error' => Translation::get('ad_passwd_fail')]); - } - $response->send(); - break; - } -} diff --git a/phpmyfaq/admin/assets/src/api/user.js b/phpmyfaq/admin/assets/src/api/user.js index 31f99be4a5..2c48eb1cdf 100644 --- a/phpmyfaq/admin/assets/src/api/user.js +++ b/phpmyfaq/admin/assets/src/api/user.js @@ -14,7 +14,7 @@ */ export const fetchUsers = async (userName) => { - return await fetch(`index.php?action=ajax&ajax=user&ajaxaction=get_user_list&q=${userName}`, { + return await fetch(`./api/user/users?filter=${userName}`, { method: 'GET', cache: 'no-cache', headers: { @@ -39,7 +39,7 @@ export const fetchUsers = async (userName) => { }; export const fetchUserData = async (userId) => { - return await fetch(`index.php?action=ajax&ajax=user&ajaxaction=get_user_data&user_id=${userId}`, { + return await fetch(`./api/user/data/${userId}`, { method: 'GET', cache: 'no-cache', headers: { @@ -60,7 +60,7 @@ export const fetchUserData = async (userId) => { }; export const fetchUserRights = async (userId) => { - return await fetch(`index.php?action=ajax&ajax=user&ajaxaction=get_user_rights&user_id=${userId}`, { + return await fetch(`./api/user/permissions/${userId}`, { method: 'GET', cache: 'no-cache', headers: { @@ -81,7 +81,7 @@ export const fetchUserRights = async (userId) => { }; export const fetchAllUsers = async () => { - return await fetch('index.php?action=ajax&ajax=user&ajaxaction=get_all_user_data', { + return await fetch('./api/user/users', { method: 'GET', cache: 'no-cache', headers: { diff --git a/phpmyfaq/admin/assets/src/user/user-list.js b/phpmyfaq/admin/assets/src/user/user-list.js index d72c0a4f0e..e8bbfd357b 100644 --- a/phpmyfaq/admin/assets/src/user/user-list.js +++ b/phpmyfaq/admin/assets/src/user/user-list.js @@ -18,7 +18,7 @@ import { addElement } from '../../../../assets/src/utils'; const activateUser = (userId, csrfToken) => { - fetch('index.php?action=ajax&ajax=user&ajaxaction=activate_user', { + fetch('./api/user/activate', { method: 'POST', headers: { Accept: 'application/json, text/plain, */*', @@ -53,7 +53,7 @@ const activateUser = (userId, csrfToken) => { const deleteUser = (userId, csrfToken) => { const message = document.getElementById('pmf-user-message'); - fetch('index.php?action=ajax&ajax=user&ajaxaction=delete_user', { + fetch('./api/user/delete', { method: 'DELETE', headers: { Accept: 'application/json, text/plain, */*', diff --git a/phpmyfaq/admin/assets/src/user/users.js b/phpmyfaq/admin/assets/src/user/users.js index a0a302504e..879560d796 100644 --- a/phpmyfaq/admin/assets/src/user/users.js +++ b/phpmyfaq/admin/assets/src/user/users.js @@ -130,6 +130,7 @@ export const handleUsers = async () => { addUserForm.classList.add('was-validated'); const userData = { + csrf, userName, realName, email, @@ -139,7 +140,7 @@ export const handleUsers = async () => { isSuperAdmin, }; - postUserData('index.php?action=ajax&ajax=user&ajaxaction=add_user&csrf=' + csrf, userData) + postUserData('./api/user/add', userData) .then(async (response) => { if (response.ok) { return response.json(); @@ -209,10 +210,15 @@ export const handleUsers = async () => { csv.unshift(header.join(',')); csv = csv.join('\r\n'); + window.open(encodeURI(csv)); + let hiddenElement = document.createElement('a'); - hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv); - hiddenElement.target = '_blank'; - hiddenElement.download = 'phpmyfaq-users-' + new Date().toISOString().substring(0, 10) + '.csv'; + hiddenElement.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURI(csv)); + hiddenElement.setAttribute('target', '_blank'); + hiddenElement.setAttribute( + 'download', + 'phpmyfaq-users-' + new Date().toISOString().substring(0, 10) + '.csv' + ); hiddenElement.click(); }) .catch((error) => { @@ -236,7 +242,7 @@ export const handleUsers = async () => { const newPassword = document.getElementById('npass').value; const passwordRepeat = document.getElementById('bpass').value; - fetch('index.php?action=ajax&ajax=user&ajaxaction=overwrite_password', { + fetch('./api/user/overwrite-password', { method: 'POST', headers: { Accept: 'application/json, text/plain, */*', @@ -250,10 +256,10 @@ export const handleUsers = async () => { }), }) .then(async (response) => { - if (response.status === 200) { + if (response.ok) { return response.json(); } - throw new Error('Network response was not ok.'); + throw new Error('Network response was not ok: ', { cause: { response } }); }) .then((response) => { message.insertAdjacentElement( @@ -262,10 +268,12 @@ export const handleUsers = async () => { ); modal.hide(); }) - .catch((error) => { + .catch(async (error) => { + const errorMessage = await error.cause.response.json(); + console.error(errorMessage.error); message.insertAdjacentElement( 'afterend', - addElement('div', { classList: 'alert alert-danger', innerText: error }) + addElement('div', { classList: 'alert alert-danger', innerText: errorMessage.error }) ); }); }); diff --git a/phpmyfaq/src/admin-routes.php b/phpmyfaq/src/admin-routes.php index 8f2498f7f3..8f050fe3e5 100644 --- a/phpmyfaq/src/admin-routes.php +++ b/phpmyfaq/src/admin-routes.php @@ -26,6 +26,7 @@ use phpMyFAQ\Controller\Administration\SearchController; use phpMyFAQ\Controller\Administration\TagController; use phpMyFAQ\Controller\Administration\UpdateController; +use phpMyFAQ\Controller\Administration\UserController; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; @@ -176,6 +177,7 @@ 'admin.api.content.tag', new Route('/content/tag', ['_controller' => [TagController::class, 'update'], '_methods' => ['PUT']]) ); + $routes->add( 'admin.api.content.tags', new Route('/content/tags', ['_controller' => [TagController::class, 'search']]) @@ -266,4 +268,47 @@ ) ); +// +// User API +// +$routes->add( + 'admin.api.user.users', + new Route('/user/users', ['_controller' => [UserController::class, 'list']]) +); + +$routes->add( + 'admin.api.user.add', + new Route('/user/add', ['_controller' => [UserController::class, 'addUser'], '_methods' => 'POST']) +); + +$routes->add( + 'admin.api.user.data', + new Route('/user/data/{userId}', ['_controller' => [UserController::class, 'userData']]) +); + +$routes->add( + 'admin.api.user.delete', + new Route('/user/delete', ['_controller' => [UserController::class, 'deleteUser'], '_methods' => 'DELETE']) +); +$routes->add( + 'admin.api.user.permissions', + new Route('/user/permissions/{userId}', ['_controller' => [UserController::class, 'userPermissions']]) +); + +$routes->add( + 'admin.api.user.activate', + new Route('/user/activate', ['_controller' => [UserController::class, 'activate'], '_methods' => 'POST']) +); + +$routes->add( + 'admin.api.user.overwrite-password', + new Route( + '/user/overwrite-password', + [ + '_controller' => [UserController::class, 'overwritePassword'], + '_methods' => 'POST' + ] + ) +); + return $routes; diff --git a/phpmyfaq/src/phpMyFAQ/Controller.php b/phpmyfaq/src/phpMyFAQ/Controller.php index c531dfaab3..9cf77eac3c 100644 --- a/phpmyfaq/src/phpMyFAQ/Controller.php +++ b/phpmyfaq/src/phpMyFAQ/Controller.php @@ -60,4 +60,17 @@ public function userHasGroupPermission(): void throw new UnauthorizedHttpException('User has no group permission.'); } } + + public function userHasUserPermission(): void + { + $configuration = Configuration::getConfigurationInstance(); + $user = CurrentUser::getCurrentUser($configuration); + if ( + !$user->perm->hasPermission($user->getUserId(), 'add_user') || + !$user->perm->hasPermission($user->getUserId(), 'edit_user') || + !$user->perm->hasPermission($user->getUserId(), 'delete_user') + ) { + throw new UnauthorizedHttpException('User has no user permission.'); + } + } } diff --git a/phpmyfaq/src/phpMyFAQ/Controller/Administration/UserController.php b/phpmyfaq/src/phpMyFAQ/Controller/Administration/UserController.php new file mode 100644 index 0000000000..25b9b5667e --- /dev/null +++ b/phpmyfaq/src/phpMyFAQ/Controller/Administration/UserController.php @@ -0,0 +1,330 @@ +userHasUserPermission(); + + $response = new JsonResponse(); + $user = CurrentUser::getCurrentUser(Configuration::getConfigurationInstance()); + + $filtered = Filter::filterVar($request->query->get('filter'), FILTER_SANITIZE_SPECIAL_CHARS); + + if ('' === $filtered) { + $allUsers = $user->getAllUsers(false); + $userData = []; + foreach ($allUsers as $userId) { + $user->getUserById($userId, true); + $userObject = new stdClass(); + $userObject->id = $user->getUserId(); + $userObject->status = $user->getStatus(); + $userObject->isSuperAdmin = $user->isSuperAdmin(); + $userObject->isVisible = $user->getUserData('is_visible'); + $userObject->displayName = Report::sanitize($user->getUserData('display_name')); + $userObject->userName = Report::sanitize($user->getLogin()); + $userObject->email = $user->getUserData('email'); + $userObject->authSource = $user->getUserAuthSource(); + $userData[] = $userObject; + } + $response->setStatusCode(Response::HTTP_OK); + $response->setData($userData); + } else { + $allUsers = []; + foreach ($user->searchUsers($filtered) as $singleUser) { + $users = new stdClass(); + $users->label = $singleUser['login']; + $users->value = (int)$singleUser['user_id']; + $allUsers[] = $users; + } + $response->setStatusCode(Response::HTTP_OK); + $response->setData($allUsers); + } + + return $response; + } + + #[Route('admin/api/user/data')] + public function userData(Request $request): JsonResponse + { + $this->userHasUserPermission(); + + $response = new JsonResponse(); + $user = CurrentUser::getCurrentUser(Configuration::getConfigurationInstance()); + + $user->getUserById($request->get('userId'), true); + $userdata = $user->userdata->get('*'); + + if (is_array($userdata)) { + $userdata['status'] = $user->getStatus(); + $userdata['login'] = Strings::htmlentities($user->getLogin(), ENT_COMPAT); + $userdata['display_name'] = Strings::htmlentities($userdata['display_name'], ENT_COMPAT); + $userdata['is_superadmin'] = $user->isSuperAdmin(); + $userdata['auth_source'] = $user->getUserAuthSource(); + } else { + $userdata = []; + } + + $response->setStatusCode(Response::HTTP_OK); + $response->setData($userdata); + + return $response; + } + + #[Route('admin/api/user/permissions')] + public function userPermissions(Request $request): JsonResponse + { + $this->userHasUserPermission(); + + $response = new JsonResponse(); + $user = CurrentUser::getCurrentUser(Configuration::getConfigurationInstance()); + + $userId = $request->get('userId'); + $user->getUserById($userId, true); + $response->setData($user->perm->getUserRights($userId)); + + return $response; + } + + #[Route('admin/api/user/activate')] + public function activate(Request $request): JsonResponse + { + $this->userHasUserPermission(); + + $response = new JsonResponse(); + $user = CurrentUser::getCurrentUser(Configuration::getConfigurationInstance()); + + $data = json_decode($request->getContent()); + if (!Token::getInstance()->verifyToken('activate-user', $data->csrfToken)) { + $response->setStatusCode(Response::HTTP_UNAUTHORIZED); + $response->setData(['error' => Translation::get('err_NotAuth')]); + return $response; + } + + $userId = Filter::filterVar($data->userId, FILTER_VALIDATE_INT); + + $user->getUserById($userId, true); + try { + if ($user->activateUser()) { + $response->setStatusCode(Response::HTTP_OK); + $response->setData(['success' => $user->getStatus()]); + } else { + $response->setStatusCode(Response::HTTP_BAD_REQUEST); + $response->setData(['error' => $user->getStatus()]); + } + } catch (TransportExceptionInterface $e) { + $response->setStatusCode(Response::HTTP_BAD_REQUEST); + $response->setData(['error' => $e->getMessage()]); + } + + return $response; + } + + /** + * @throws Exception + */ + #[Route('admin/api/user/overwrite-password')] + public function overwritePassword(Request $request): JsonResponse + { + $this->userHasUserPermission(); + + $response = new JsonResponse(); + $configuration = Configuration::getConfigurationInstance(); + $user = CurrentUser::getCurrentUser($configuration); + + $data = json_decode($request->getContent()); + + $userId = Filter::filterVar($data->userId, FILTER_VALIDATE_INT); + $csrfToken = Filter::filterVar($data->csrf, FILTER_SANITIZE_SPECIAL_CHARS); + $newPassword = Filter::filterVar($data->newPassword, FILTER_SANITIZE_SPECIAL_CHARS); + $retypedPassword = Filter::filterVar($data->passwordRepeat, FILTER_SANITIZE_SPECIAL_CHARS); + + if (!Token::getInstance()->verifyToken('overwrite-password', $csrfToken)) { + $response->setStatusCode(Response::HTTP_UNAUTHORIZED); + $response->setData(['error' => Translation::get('err_NotAuth')]); + return $response; + } + + if (strlen($newPassword) <= 7 || strlen($retypedPassword) <= 7) { + $response->setStatusCode(Response::HTTP_BAD_REQUEST); + $response->setData(['error' => Translation::get('ad_passwd_fail')]); + return $response; + } + + $user->getUserById($userId, true); + + $auth = new Auth($configuration); + $authSource = $auth->selectAuth($user->getAuthSource('name')); + $authSource->selectEncType($user->getAuthData('encType')); + + if ($newPassword === $retypedPassword) { + if (!$user->changePassword($newPassword)) { + $response->setStatusCode(Response::HTTP_BAD_REQUEST); + $response->setData(['error' => Translation::get('ad_passwd_fail')]); + $response->send(); + } + $response->setStatusCode(Response::HTTP_OK); + $response->setData(['success' => Translation::get('ad_passwdsuc')]); + } else { + $response->setStatusCode(Response::HTTP_BAD_REQUEST); + $response->setData(['error' => Translation::get('ad_passwd_fail')]); + } + + return $response; + } + + #[Route('admin/api/user/delete')] + public function deleteUser(Request $request): JsonResponse + { + $this->userHasUserPermission(); + + $response = new JsonResponse(); + $configuration = Configuration::getConfigurationInstance(); + $user = CurrentUser::getCurrentUser($configuration); + + $data = json_decode($request->getContent()); + + if (!Token::getInstance()->verifyToken('delete-user', $data->csrfToken)) { + $response->setStatusCode(Response::HTTP_UNAUTHORIZED); + $response->setData(['error' => Translation::get('err_NotAuth')]); + return $response; + } + + $userId = Filter::filterVar($data->userId, FILTER_VALIDATE_INT); + + $user->getUserById($userId, true); + if ($user->getStatus() == 'protected' || $userId == 1) { + $message = '

' . Translation::get('ad_user_error_protectedAccount') . '

'; + } else { + if (!$user->deleteUser()) { + $message = Translation::get('ad_user_error_delete'); + } else { + $category = new Category($configuration, [], false); + $category->moveOwnership((int) $userId, 1); + + // Remove the user from groups + if ('basic' !== $configuration->get('security.permLevel')) { + $permissions = Permission::selectPerm('medium', $configuration); + $permissions->removeFromAllGroups($userId); + } + + $message = Alert::success('ad_user_deleted'); + } + } + $response->setStatusCode(Response::HTTP_OK); + $response->setData($message); + + return $response; + } + + #[Route('admin/api/user/add')] + public function addUser(Request $request): JsonResponse + { + $this->userHasUserPermission(); + + $response = new JsonResponse(); + $configuration = Configuration::getConfigurationInstance(); + + $data = json_decode($request->getContent()); + + if (!Token::getInstance()->verifyToken('add-user', $data->csrf)) { + $response->setStatusCode(Response::HTTP_UNAUTHORIZED); + $response->setData(['error' => Translation::get('err_NotAuth')]); + return $response; + } + + $errorMessage = []; + $successMessage = ''; + + $userName = Filter::filterVar($data->userName, FILTER_SANITIZE_SPECIAL_CHARS); + $userRealName = Filter::filterVar($data->realName, FILTER_SANITIZE_SPECIAL_CHARS); + $userEmail = Filter::filterVar($data->email, FILTER_VALIDATE_EMAIL); + $automaticPassword = Filter::filterVar($data->automaticPassword, FILTER_VALIDATE_BOOLEAN); + $userPassword = Filter::filterVar($data->password, FILTER_SANITIZE_SPECIAL_CHARS); + $userPasswordConfirm = Filter::filterVar($data->passwordConfirm, FILTER_SANITIZE_SPECIAL_CHARS); + $userIsSuperAdmin = Filter::filterVar($data->isSuperAdmin, FILTER_VALIDATE_BOOLEAN); + + $newUser = new User($configuration); + + if (!$newUser->isValidLogin($userName)) { + $errorMessage[] = Translation::get('ad_user_error_loginInvalid'); + } + if ($newUser->getUserByLogin($userName)) { + $errorMessage[] = Translation::get('ad_adus_exerr'); + } + if ($userRealName === '') { + $errorMessage[] = Translation::get('ad_user_error_noRealName'); + } + if (is_null($userEmail)) { + $errorMessage[] = Translation::get('ad_user_error_noEmail'); + } + if (!$automaticPassword) { + if (strlen($userPassword) <= 7 || strlen($userPasswordConfirm) <= 7) { + $errorMessage[] = Translation::get('ad_passwd_fail'); + } + } else { + $userPassword = $newUser->createPassword(8, false); + } + + if (count($errorMessage) === 0) { + if (!$newUser->createUser($userName, $userPassword)) { + $errorMessage[] = $newUser->error(); + } else { + $newUser->userdata->set(['display_name', 'email', 'is_visible'], [$userRealName, $userEmail, 0]); + $newUser->setStatus('active'); + $newUser->setSuperAdmin((bool)$userIsSuperAdmin); + $mailHelper = new MailHelper($configuration); + try { + $mailHelper->sendMailToNewUser($newUser, $userPassword); + } catch (Exception | TransportExceptionInterface $e) { + // @todo catch exception + } + $successMessage = [ + 'success' => Translation::get('ad_adus_suc'), + 'id' => $newUser->getUserId(), + 'status' => $newUser->getStatus(), + 'isSuperAdmin' => (bool)$userIsSuperAdmin, + 'isVisible' => (bool) $newUser->userdata->get('is_visible'), + 'realName' => $userRealName, + 'userName' => $userName, + 'email' => $userEmail, + 'editTranslationString' => Translation::get('ad_user_edit') + ]; + } + + $response->setStatusCode(Response::HTTP_OK); + $response->setData($successMessage); + return $response; + } + + $response->setStatusCode(Response::HTTP_BAD_REQUEST); + $response->setData($errorMessage); + + return $response; + } +}