diff --git a/bbbeasy-backend/app/config/access.ini b/bbbeasy-backend/app/config/access.ini index f0dd20ee..5d54e17d 100644 --- a/bbbeasy-backend/app/config/access.ini +++ b/bbbeasy-backend/app/config/access.ini @@ -44,4 +44,6 @@ allow GET @get_reset_token = * allow GET @roles_permissions_collect = * ; settings routes -allow POST @settings_save_logo = * \ No newline at end of file +allow POST @settings_save_logo = * + +allow POST @reset_password_attempts = * \ No newline at end of file diff --git a/bbbeasy-backend/app/config/routes.ini b/bbbeasy-backend/app/config/routes.ini index f0bc7420..799f1264 100644 --- a/bbbeasy-backend/app/config/routes.ini +++ b/bbbeasy-backend/app/config/routes.ini @@ -57,10 +57,12 @@ GET @roles_collect : /api/roles/collect = Actions\Roles\Collect->ex GET @roles_permissions_collect : /api/roles-permissions = Actions\RolesPermissions\Collect->execute ; users routes -GET @users_index : /api/users = Actions\Users\Index->show -POST @users_add : /api/users = Actions\Users\Add->save -PUT @users_edit : /api/users/@id = Actions\Users\Edit->save -DELETE @user_delete : /api/users/@id = Actions\Users\Delete->execute +GET @users_index : /api/users = Actions\Users\Index->show +POST @users_add : /api/users = Actions\Users\Add->save +PUT @users_edit : /api/users/@id = Actions\Users\Edit->save +DELETE @user_delete : /api/users/@id = Actions\Users\Delete->execute +POST @reset_password_attempts : /api/users/reset-attempts/@id = Actions\Users\ResetPasswordAttempts->save + ; presets routes GET @presets_index : /api/presets/@user_id = Actions\Presets\Index->show diff --git a/bbbeasy-backend/app/src/Actions/Users/ResetPasswordAttempts.php b/bbbeasy-backend/app/src/Actions/Users/ResetPasswordAttempts.php new file mode 100644 index 00000000..280f3548 --- /dev/null +++ b/bbbeasy-backend/app/src/Actions/Users/ResetPasswordAttempts.php @@ -0,0 +1,66 @@ +. + */ + + +namespace Actions\Users; + +use Actions\Base as BaseAction; +use Actions\RequirePrivilegeTrait; +use Models\User; +use Enum\ResponseCode; + +/** + * Class ResetPasswordAttempts. + */ +class ResetPasswordAttempts extends BaseAction +{ + use RequirePrivilegeTrait; + + /** + * @param \Base $f3 + * @param array $params + */ + public function save($f3, $params): void + { + $user = new User(); + $userId = $params['id']; + $user->load(['id = ?', $userId]); + $errorMessage = 'Password attempts could not be reset'; + if ($user->valid()) { + + try { + $user->getPasswordAttemptsById($userId); + $this->logger->info('reset password attempts', ['user' => $userId]); + + } catch (\Exception $e) { + $this->logger->error($errorMessage, ['user' => $userId, 'error' => $e->getMessage()]); + $this->renderJson(['errors' => $e->getMessage()], ResponseCode::HTTP_INTERNAL_SERVER_ERROR); + + return; + } + $this->renderJson(['result' => 'success', 'message' => 'Password attempts have been reset']); + } else { + $this->logger->error($errorMessage); + $this->renderJson([], ResponseCode::HTTP_NOT_FOUND); + } + } +} \ No newline at end of file diff --git a/bbbeasy-backend/app/src/Models/User.php b/bbbeasy-backend/app/src/Models/User.php index a8d9b00e..26e53429 100644 --- a/bbbeasy-backend/app/src/Models/User.php +++ b/bbbeasy-backend/app/src/Models/User.php @@ -187,6 +187,11 @@ public function countActiveUsers(array $ids = null): int return (int) $result[0]['total']; } + public function getPasswordAttemptsById($userId) + { + return $this->db->exec('UPDATE users SET password_attempts = 3 WHERE id = ?', $userId); + } + public function verifyPassword($password): bool { return password_verify(trim($password), $this->password); diff --git a/bbbeasy-frontend/src/components/Users.tsx b/bbbeasy-frontend/src/components/Users.tsx index 2617a4e4..71a0ec95 100644 --- a/bbbeasy-frontend/src/components/Users.tsx +++ b/bbbeasy-frontend/src/components/Users.tsx @@ -22,8 +22,8 @@ import EN_US from '../locale/en-US.json'; import { t } from 'i18next'; import { PageHeader } from '@ant-design/pro-layout'; -import { Alert, Button, Form, Input, Modal, Popconfirm, Select, Space, Tag, Typography } from 'antd'; -import { DeleteOutlined, EditOutlined, QuestionCircleOutlined } from '@ant-design/icons'; +import { Alert, Button, Form, Input, Modal, Popconfirm, Select, Space, Tag, Typography, Dropdown, Menu } from 'antd'; +import { DeleteOutlined, EditOutlined, QuestionCircleOutlined, MoreOutlined } from '@ant-design/icons'; import { FormInstance } from 'antd/lib/form'; import { CompareRecords } from '../functions/compare.function'; @@ -36,6 +36,7 @@ import EditableTableColumnSearch from './EditableTableColumnSearch'; import AuthService from '../services/auth.service'; import UsersService from '../services/users.service'; import RolesService from '../services/roles.service'; +import LocaleService from "../services/locale.service"; import { TableColumnType } from '../types/TableColumnType'; import { UserType } from '../types/UserType'; @@ -305,6 +306,17 @@ const Users = () => { } }; + // Reset password attempts + const handleResetPasswordAttemptsClick = (key: number) => { + UsersService.reset_password_attempts(key) + .then(() => { + Notifications.openNotificationWithIcon('success', t('password.resetAttempts')); + }) + .catch((error) => { + console.log(error); + }); + } + // delete const handleDelete = (key: number) => { UsersService.delete_user(key) @@ -470,6 +482,21 @@ const Users = () => { )} + + handleResetPasswordAttemptsClick(record.key)}> + + + + } + placement={LocaleService.direction == 'rtl' ? 'topRight' : 'topLeft'} + trigger={['click']} + arrow + > + + ); }, diff --git a/bbbeasy-frontend/src/locale/ar-TN.json b/bbbeasy-frontend/src/locale/ar-TN.json index 8b5e3c06..fec1ff9a 100644 --- a/bbbeasy-frontend/src/locale/ar-TN.json +++ b/bbbeasy-frontend/src/locale/ar-TN.json @@ -33,7 +33,8 @@ "label": "كلمة المرور", "required": "كلمة المرور مطلوبة", "size": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل", - "invalid": "كلمة المرور غير صحيحة" + "invalid": "كلمة المرور غير صحيحة", + "resetAttempts": "تمت إعادة تعيين محاولات كلمة المرور" }, "join-us": "إنضم إلينا", "register-now": "قم بالتسجيل الآن وانضم إلى مجتمعنا ", @@ -185,6 +186,7 @@ "permissions": { "label": "الصلاحيات" }, + "reset_password_attempts": "إعادة تعيين كلمة المرور", "search": "البحث", "reset": "إعادة التهيئة", "filter": "التصفية", diff --git a/bbbeasy-frontend/src/locale/en-US.json b/bbbeasy-frontend/src/locale/en-US.json index 499fd181..929ebac6 100644 --- a/bbbeasy-frontend/src/locale/en-US.json +++ b/bbbeasy-frontend/src/locale/en-US.json @@ -33,7 +33,8 @@ "label": "Password", "required": "Password is required", "size": "Password must have at least 8 characters", - "invalid": "Invalid password" + "invalid": "Invalid password", + "resetAttempts": "Password attempts have been reset" }, "join-us": "Join us", "register-now": "Register now and join our community ", @@ -186,6 +187,7 @@ "permissions": { "label": "Permissions" }, + "reset_password_attempts": "Reset password attempts", "search": "Search", "reset": "Reset", "filter": "Filter", diff --git a/bbbeasy-frontend/src/locale/fr-FR.json b/bbbeasy-frontend/src/locale/fr-FR.json index ddeaf172..ec8872a9 100644 --- a/bbbeasy-frontend/src/locale/fr-FR.json +++ b/bbbeasy-frontend/src/locale/fr-FR.json @@ -33,7 +33,8 @@ "label": "Mot de passe", "required": "Le mot de passe est obligatoire", "size": "Le mot de passe doit contenir au moins 8 caractères", - "invalid": "Mot de passe incorrect" + "invalid": "Mot de passe incorrect", + "resetAttempts": "Les tentatives de mot de passe ont été réinitialisées" }, "join-us": "Rejoignez-nous", "register-now": "Inscrivez-vous dès maintenant et rejoignez notre communauté ", @@ -185,6 +186,7 @@ "permissions": { "label": "Permissions" }, + "reset_password_attempts": "réinitialiser les tentatives de mot de passe", "search": "Chercher", "reset": "Réinitialiser", "filter": "Filtrer", diff --git a/bbbeasy-frontend/src/routing/backend-config.tsx b/bbbeasy-frontend/src/routing/backend-config.tsx index bc12758d..2b9751bc 100644 --- a/bbbeasy-frontend/src/routing/backend-config.tsx +++ b/bbbeasy-frontend/src/routing/backend-config.tsx @@ -49,6 +49,7 @@ export const apiRoutes = { ADD_USER_URL: API_URL + '/users', EDIT_USER_URL: API_URL + '/users/', DELETE_USER_URL: API_URL + '/users/', + RESET_PASSWORD_ATTEMPTS_URL: API_URL + '/users/reset-attempts/', LIST_LABEL_URL: API_URL + '/labels', ADD_LABEL_URL: API_URL + '/labels', diff --git a/bbbeasy-frontend/src/services/users.service.ts b/bbbeasy-frontend/src/services/users.service.ts index 7b69d46f..b3aa3d52 100644 --- a/bbbeasy-frontend/src/services/users.service.ts +++ b/bbbeasy-frontend/src/services/users.service.ts @@ -36,6 +36,10 @@ class UsersService { }); } + reset_password_attempts(id: number) { + return axiosInstance.post(apiRoutes.RESET_PASSWORD_ATTEMPTS_URL + id); + } + edit_user(data: object, id: number) { return axiosInstance.put(apiRoutes.EDIT_USER_URL + id, { data,