diff --git a/core/src/Employees/User/Api/EmployeesActionManager.php b/core/src/Employees/User/Api/EmployeesActionManager.php
index 06b6f0ca..a1779107 100644
--- a/core/src/Employees/User/Api/EmployeesActionManager.php
+++ b/core/src/Employees/User/Api/EmployeesActionManager.php
@@ -56,9 +56,9 @@ class EmployeesActionManager extends SubActionManager
if (!empty($childCompaniesIds)) {
$childStructureSubordinates
= $obj->Find(
- "department in (" . implode(',', $childCompaniesIds) . ") and id != ?",
- array($cemp)
- );
+ "department in (" . implode(',', $childCompaniesIds) . ") and id != ?",
+ array($cemp)
+ );
$subordinates = array_merge($subordinates, $childStructureSubordinates);
}
@@ -147,6 +147,10 @@ class EmployeesActionManager extends SubActionManager
return new IceResponse(IceResponse::ERROR, "Error occurred while changing password");
}
+ if (!PasswordManager::verifyPassword($req->current, $user->password)) {
+ return new IceResponse(IceResponse::ERROR, "Current password is incorrect");
+ }
+
$passwordStrengthResponse = PasswordManager::isQualifiedPassword($req->pwd);
if ($passwordStrengthResponse->getStatus() === IceResponse::ERROR) {
return $passwordStrengthResponse;
@@ -158,6 +162,6 @@ class EmployeesActionManager extends SubActionManager
return new IceResponse(IceResponse::ERROR, $user->ErrorMsg());
}
- return new IceResponse(IceResponse::SUCCESS, $user);
+ return new IceResponse(IceResponse::SUCCESS, []);
}
}
diff --git a/web/api/CustomAction.js b/web/api/CustomAction.js
new file mode 100644
index 00000000..d021a9b4
--- /dev/null
+++ b/web/api/CustomAction.js
@@ -0,0 +1,26 @@
+const axios = require('axios');
+
+class CustomAction {
+ constructor(adapter) {
+ this.adapter = adapter;
+ }
+
+ execute(subAction, module, request, isPost) {
+ if (!isPost) {
+ return axios.get(
+ this.adapter.moduleRelativeURL,
+ {
+ params: {
+ t: this.adapter.table, a: 'ca', sa: subAction, mod: module, req: request,
+ },
+ },
+ );
+ }
+
+ return axios.post(this.moduleRelativeURL, {
+ t: this.adapter.table, a: 'ca', sa: subAction, mod: module, req: request,
+ });
+ }
+}
+
+export default CustomAction;
diff --git a/web/components/UpdatePasswordModal.js b/web/components/UpdatePasswordModal.js
new file mode 100644
index 00000000..5c648f25
--- /dev/null
+++ b/web/components/UpdatePasswordModal.js
@@ -0,0 +1,232 @@
+import React, {Component} from 'react';
+import {
+ Form,
+ Modal,
+ Input,
+ Button,
+ message,
+} from 'antd';
+import CustomAction from '../api/CustomAction';
+
+class UpdatePasswordModal extends React.Component {
+
+ state = {
+ loading: false,
+ passwordHasError: false,
+ passwordState: { hasFeedback: false, validateStatus:'', help:'Password must include at least one number, one lowercase letter, one uppercase letter and a symbol' },
+ confirmationHasError: false,
+ confirmationState: { hasFeedback: false, validateStatus:'', help:'' },
+ };
+
+ constructor(props) {
+ super(props);
+ this.formRef = React.createRef();
+ this.customAction = new CustomAction(this.props.adapter);
+ }
+
+ componentDidMount() {
+ message.config({
+ top: 40,
+ });
+ }
+
+ clearConfirmFeedback = () => {
+ this.setState({confirmationHasError: false});
+ this.setState({
+ confirmationState: {
+ hasFeedback : false,
+ validateStatus:'',
+ help:'',
+ }
+ });
+ }
+
+ updatePasswordState(value) {
+ const passwordValidationResult = this.validatePassword(value);
+ if (passwordValidationResult !== null) {
+ this.setState({passwordHasError: true});
+ this.setState({
+ passwordState: {
+ hasFeedback : true,
+ validateStatus:'error',
+ help:passwordValidationResult,
+ }
+ });
+
+ return false;
+ } else {
+ this.setState({passwordHasError: false});
+ this.setState({
+ passwordState: {
+ hasFeedback : true,
+ validateStatus:'success',
+ help:'',
+ }
+ });
+ }
+
+ return true;
+ }
+
+ updateConfirmPasswordState(values) {
+ if (values.confirm !== values.new) {
+ this.setState({confirmationHasError: true});
+ this.setState({
+ confirmationState: {
+ hasFeedback : true,
+ validateStatus:'error',
+ help:'Passwords don\'t match',
+ }
+ });
+
+ return false;
+ } else {
+ this.setState({confirmationHasError: false});
+ this.setState({
+ confirmationState: {
+ hasFeedback : false,
+ validateStatus:'',
+ help:'',
+ }
+ });
+ }
+
+ return true;
+ }
+
+ handleOk = () => {
+ const from = this.formRef.current;
+ from
+ .validateFields()
+ .then((values) => {
+ if (this.updatePasswordState(values.new) && this.updateConfirmPasswordState(values)) {
+ this.updatePassword(values.current, values.new)
+ .then((response) => {
+ const data = response.data;
+ console.log(data);
+ if (data.status === 'SUCCESS') {
+ this.handleCancel();
+ message.success(this.props.adapter.gt('Password updated'));
+ } else {
+ message.error(
+ `${this.props.adapter.gt('Error updating password')}: ${this.props.adapter.gt(data.data)}`
+ );
+ }
+ }).catch((error) => {
+ message.error(
+ `${this.props.adapter.gt('Error updating password')}`
+ );
+ console.log(error.message);
+ });
+ }
+ })
+ .catch((info) => {
+ this.setState({ loading: false });
+ });
+ }
+
+ handleCancel = () => {
+ if (this.formRef.current) {
+ this.formRef.current.resetFields();
+ }
+ this.props.closeModal();
+ }
+
+ updatePassword = (oldPassword, newPassword) => {
+ const req = { current: oldPassword ? oldPassword : '', pwd: newPassword };
+ const reqJson = JSON.stringify(req);
+
+ const callBackData = [];
+ callBackData.callBackData = [];
+ callBackData.callBackSuccess = 'changePasswordSuccessCallBack';
+ callBackData.callBackFail = 'changePasswordFailCallBack';
+
+ return this.customAction.execute('changePassword', 'modules=employees', reqJson);
+
+ }
+
+ validatePassword = (password) => {
+ if (password.length < 8) {
+ return this.props.adapter.gt('Password too short');
+ }
+
+ if (password.length > 20) {
+ return this.props.adapter.gt('Password too long');
+ }
+
+ const numberTester = /.*[0-9]+.*$/;
+ if (!password.match(numberTester)) {
+ return this.props.adapter.gt('Password must include at least one number');
+ }
+
+ const lowerTester = /.*[a-z]+.*$/;
+ if (!password.match(lowerTester)) {
+ return this.props.adapter.gt('Password must include at least one lowercase letter');
+ }
+
+ const upperTester = /.*[A-Z]+.*$/;
+ if (!password.match(upperTester)) {
+ return this.props.adapter.gt('Password must include at least one uppercase letter');
+ }
+
+ const symbolTester = /.*[\W]+.*$/;
+ if (!password.match(symbolTester)) {
+ return this.props.adapter.gt('Password must include at least one symbol');
+ }
+
+ return null;
+ }
+
+ render() {
+ const layout = {
+ labelCol: { span: 8 },
+ wrapperCol: { span: 16 },
+ };
+
+ return (
+
+ {this.props.adapter.gt('Cancel')}
+ ,
+ ,
+ ]}
+ >
+
+
+
+ { this.state.passwordHasError &&
+
+ this.updatePasswordState(event.target.value)}/>
+
+ }
+ { !this.state.passwordHasError &&
+
+ this.updatePasswordState(event.target.value)}/>
+
+ }
+ { this.state.confirmationHasError &&
+
+ this.clearConfirmFeedback()}/>
+
+ }
+ { !this.state.confirmationHasError &&
+
+ this.clearConfirmFeedback()}/>
+
+ }
+
+
+
+ )
+ }
+}
+
+export default UpdatePasswordModal;
diff --git a/web/modules/src/employees/components/EmployeeProfile.js b/web/modules/src/employees/components/EmployeeProfile.js
index 6c0fa360..19f18b49 100644
--- a/web/modules/src/employees/components/EmployeeProfile.js
+++ b/web/modules/src/employees/components/EmployeeProfile.js
@@ -1,37 +1,32 @@
-import React, {Component} from 'react';
+import React from 'react';
import {
Col,
Card,
- Badge,
Avatar,
- Input,
Row,
Descriptions,
Typography,
- Table,
Space,
- Button,
Tag,
- message,
Tabs,
- Spin,
Skeleton
} from 'antd';
import {
- FilterOutlined,
EditOutlined,
PhoneTwoTone,
MailTwoTone,
SyncOutlined,
+ LockOutlined,
} from '@ant-design/icons';
import TagList from "../../../../components/TagList";
-const { Search } = Input;
+import UpdatePasswordModal from "../../../../components/UpdatePasswordModal";
const { Title, Text } = Typography;
const { TabPane } = Tabs;
class EmployeeProfile extends React.Component {
state = {
loading: true,
+ showPasswordResetModal: false,
};
constructor(props) {
@@ -42,6 +37,10 @@ class EmployeeProfile extends React.Component {
this.setState({ loading: value });
}
+ setShowPasswordUpdate(value) {
+ this.setState({ showPasswordResetModal: value });
+ }
+
updateProfileImage() {
showUploadDialog(
`profile_image_${this.props.element.id}_${(new Date()).getTime()}`,
@@ -71,6 +70,33 @@ class EmployeeProfile extends React.Component {
>);
}
+ getEditButtonJsxWithPassword() {
+ return (<>
+ {this.state.loading &&
+ } color="processing">
+ {this.props.adapter.gt('Edit')}
+
+ }
+ {!this.state.loading &&
+ } color="processing"
+ onClick={() => modJs.edit(this.props.element.id)}>
+ {this.props.adapter.gt('Edit')}
+
+ }
+ } color="volcano" onClick={() => this.setShowPasswordUpdate(true)}>
+ {this.props.adapter.gt('Update Password')}
+
+ >);
+ }
+
+ getUpdatePasswordButtonJsx() {
+ return (<>
+ } color="processing">
+ {this.props.adapter.gt('Update Password')}
+
+ >);
+ }
+
getTabViewEmployeeFilterButtonJsx(tab) {
return (
} color="processing"
@@ -86,10 +112,15 @@ class EmployeeProfile extends React.Component {
}
return (
<>
+ {this.setState({ showPasswordResetModal: false })}}
+ adapter={this.props.adapter}
+ />