Merge pull request #65 from stephb9959/main

Version 2.4.0
This commit is contained in:
Charles
2021-11-15 16:58:40 -05:00
committed by GitHub
12 changed files with 159 additions and 71 deletions

18
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ucentral-client",
"version": "2.3.20",
"version": "2.4.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ucentral-client",
"version": "2.3.20",
"version": "2.4.0",
"dependencies": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1",
@@ -32,7 +32,7 @@
"react-tooltip": "^4.2.21",
"react-widgets": "^5.1.1",
"sass": "^1.35.1",
"ucentral-libs": "^1.0.29",
"ucentral-libs": "^1.0.30",
"uuid": "^8.3.2"
},
"devDependencies": {
@@ -14842,9 +14842,9 @@
}
},
"node_modules/ucentral-libs": {
"version": "1.0.29",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-1.0.29.tgz",
"integrity": "sha512-yeuzfdk15YqUW7/BdAdR8PxF0IIGxubTfkJQBloZqOFWIfBb/b//lDWjQUKj2DkgxxAW3rY3XbmzwCU9UJuMPg==",
"version": "1.0.30",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-1.0.30.tgz",
"integrity": "sha512-rYSMUZZ6zVa3PokYUlvAydDfYQE0fUTWY8KClbCsuq8S9N+KwSlGsHVZRw/Vax9OyKh6jLBTWcRnQYkx9DG49g==",
"dependencies": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1",
@@ -27716,9 +27716,9 @@
}
},
"ucentral-libs": {
"version": "1.0.29",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-1.0.29.tgz",
"integrity": "sha512-yeuzfdk15YqUW7/BdAdR8PxF0IIGxubTfkJQBloZqOFWIfBb/b//lDWjQUKj2DkgxxAW3rY3XbmzwCU9UJuMPg==",
"version": "1.0.30",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-1.0.30.tgz",
"integrity": "sha512-rYSMUZZ6zVa3PokYUlvAydDfYQE0fUTWY8KClbCsuq8S9N+KwSlGsHVZRw/Vax9OyKh6jLBTWcRnQYkx9DG49g==",
"requires": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "ucentral-client",
"version": "2.3.20",
"version": "2.4.0",
"dependencies": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1",
@@ -26,7 +26,7 @@
"react-tooltip": "^4.2.21",
"react-widgets": "^5.1.1",
"sass": "^1.35.1",
"ucentral-libs": "^1.0.29",
"ucentral-libs": "^1.0.30",
"uuid": "^8.3.2"
},
"main": "index.js",

View File

@@ -686,7 +686,7 @@
"check_phone": "Bitte überprüfen Sie Ihr Telefon auf Ihren Validierungscode",
"confirm_new_password": "Bestätige neues Passwort",
"create": "Benutzer erstellen",
"create_failure": "Fehler beim Erstellen des Benutzers. Bitte stellen Sie sicher, dass diese E-Mail-Adresse nicht bereits mit einem Konto verknüpft ist.",
"create_failure": "Fehler beim Erstellen des Benutzers: {{error}}",
"create_success": "Benutzer erfolgreich erstellt",
"creating": "Benutzer erstellen ...",
"delete_avatar": "Avatar löschen",

View File

@@ -686,7 +686,7 @@
"check_phone": "Please check your phone for your validation code",
"confirm_new_password": "Confirm New Password",
"create": "Create User",
"create_failure": "Error while creating user. Please make sure this email address is not already linked to an account.",
"create_failure": "Error while creating user: {{error}}",
"create_success": "User Created Successfully",
"creating": "Creating User...",
"delete_avatar": "Delete Avatar",

View File

@@ -686,7 +686,7 @@
"check_phone": "Por favor revise su teléfono para su código de validación",
"confirm_new_password": "confirmar nueva contraseña",
"create": "Crear usuario",
"create_failure": "Error al crear usuario. Asegúrese de que esta dirección de correo electrónico no esté vinculada a una cuenta.",
"create_failure": "Error al crear el usuario: {{error}}",
"create_success": "Usuario creado con éxito",
"creating": "Creando usuario ...",
"delete_avatar": "Eliminar avatar",

View File

@@ -686,7 +686,7 @@
"check_phone": "Veuillez vérifier votre téléphone pour votre code de validation",
"confirm_new_password": "Confirmer le nouveau mot de passe",
"create": "Créer un utilisateur",
"create_failure": "Erreur lors de la création de l'utilisateur. Veuillez vous assurer que cette adresse e-mail n'est pas déjà liée à un compte.",
"create_failure": "Erreur lors de la création de l'utilisateur : {{error}}",
"create_success": "L'utilisateur a été créé avec succès",
"creating": "Création de l'utilisateur...",
"delete_avatar": "Supprimer l'avatar",

View File

@@ -686,7 +686,7 @@
"check_phone": "Por favor, verifique o seu telefone para o seu código de validação",
"confirm_new_password": "confirme a nova senha",
"create": "Criar usuário",
"create_failure": "Erro ao criar usuário. Certifique-se de que este endereço de e-mail ainda não esteja vinculado a uma conta.",
"create_failure": "Erro ao criar usuário: {{error}}",
"create_success": "Usuário criado com sucesso",
"creating": "Criando usuário ...",
"delete_avatar": "Apagar Avatar",

View File

@@ -27,7 +27,7 @@ const initialState = {
error: false,
},
userRole: {
value: 'admin',
value: 'accounting',
error: false,
},
notes: {
@@ -42,16 +42,11 @@ const initialState = {
},
};
const CreateUserModal = ({ show, toggle, getUsers }) => {
const CreateUserModal = ({ show, toggle, getUsers, policies }) => {
const { t } = useTranslation();
const { currentToken, endpoints } = useAuth();
const { addToast } = useToast();
const [loading, setLoading] = useState(false);
const [policies, setPolicies] = useState({
passwordPolicy: '',
passwordPattern: '',
accessPolicy: '',
});
const [formFields, updateFieldWithId, updateField, setFormFields] = useFormFields(initialState);
const toggleChange = () => {
@@ -107,10 +102,10 @@ const CreateUserModal = ({ show, toggle, getUsers }) => {
});
toggle();
})
.catch(() => {
.catch((e) => {
addToast({
title: t('common.error'),
body: t('user.create_failure'),
body: t('user.create_failure', { error: e.response?.data?.ErrorDescription }),
color: 'danger',
autohide: true,
});
@@ -122,23 +117,6 @@ const CreateUserModal = ({ show, toggle, getUsers }) => {
setLoading(false);
}
};
const getPasswordPolicy = () => {
axiosInstance
.post(`${endpoints.owsec}/api/v1/oauth2?requirements=true`, {})
.then((response) => {
const newPolicies = response.data;
newPolicies.accessPolicy = `${endpoints.owsec}${newPolicies.accessPolicy}`;
newPolicies.passwordPolicy = `${endpoints.owsec}${newPolicies.passwordPolicy}`;
setPolicies(response.data);
})
.catch(() => {});
};
useEffect(() => {
if (policies.passwordPattern.length === 0) getPasswordPolicy();
}, []);
useEffect(() => {
setFormFields(initialState);
}, [show]);
@@ -177,6 +155,7 @@ CreateUserModal.propTypes = {
show: PropTypes.bool.isRequired,
toggle: PropTypes.func.isRequired,
getUsers: PropTypes.func.isRequired,
policies: PropTypes.instanceOf(Object).isRequired,
};
export default React.memo(CreateUserModal);

View File

@@ -36,7 +36,7 @@ const initialState = {
editable: true,
},
userRole: {
value: '',
value: 'accounting',
error: false,
editable: true,
},
@@ -46,7 +46,7 @@ const initialState = {
},
};
const EditUserModal = ({ show, toggle, userId, getUsers }) => {
const EditUserModal = ({ show, toggle, userId, getUsers, policies }) => {
const { t } = useTranslation();
const { currentToken, endpoints } = useAuth();
const { addToast } = useToast();
@@ -54,23 +54,6 @@ const EditUserModal = ({ show, toggle, userId, getUsers }) => {
const [initialUser, setInitialUser] = useState({});
const [editing, setEditing] = useState(false);
const [user, updateWithId, updateWithKey, setUser] = useUser(initialState);
const [policies, setPolicies] = useState({
passwordPolicy: '',
passwordPattern: '',
accessPolicy: '',
});
const getPasswordPolicy = () => {
axiosInstance
.post(`${endpoints.owsec}/api/v1/oauth2?requirements=true`, {})
.then((response) => {
const newPolicies = response.data;
newPolicies.accessPolicy = `${endpoints.owsec}${newPolicies.accessPolicy}`;
newPolicies.passwordPolicy = `${endpoints.owsec}${newPolicies.passwordPolicy}`;
setPolicies(response.data);
})
.catch(() => {});
};
const getUser = () => {
const options = {
@@ -209,9 +192,6 @@ const EditUserModal = ({ show, toggle, userId, getUsers }) => {
if (userId) {
getUser();
}
if (policies.passwordPattern.length === 0) {
getPasswordPolicy();
}
}, [userId]);
useEffect(() => {
@@ -243,6 +223,7 @@ EditUserModal.propTypes = {
show: PropTypes.bool.isRequired,
toggle: PropTypes.func.isRequired,
getUsers: PropTypes.func.isRequired,
policies: PropTypes.instanceOf(Object).isRequired,
};
export default React.memo(EditUserModal);

View File

@@ -133,7 +133,7 @@ const Login = () => {
const onKeyDown = (event, action) => {
if (event.code === 'Enter') {
action();
action(event);
}
};
@@ -305,6 +305,107 @@ const Login = () => {
}
};
const submitForm = (event) => {
event.preventDefault();
setLoginResponse(initialResponseState);
setLoading(true);
let token = '';
const parameters = {
userId: event.target?.username?.value,
password: event.target?.password?.value,
};
if (formType === 'change-password') {
parameters.newPassword = fields.newpassword.value;
}
axiosInstance
.post(`${fields.ucentralsecurl.value}/api/v1/oauth2`, parameters)
.then((response) => {
// If there's MFA to do
if (response.data.method && response.data.created) {
setFormType(`validation-${response.data.method}-${response.data.uuid}`);
return null;
}
if (response.data.userMustChangePassword) {
setFormType('change-password');
return null;
}
setItem('access_token', response.data.access_token);
token = response.data.access_token;
return axiosInstance.get(`${fields.ucentralsecurl.value}/api/v1/systemEndpoints`, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${response.data.access_token}`,
},
});
})
.then((response) => {
if (response) {
const endpoints = {
owsec: fields.ucentralsecurl.value,
};
for (const endpoint of response.data.endpoints) {
endpoints[endpoint.type] = endpoint.uri;
}
if (endpoints.owgw) getGatewayUIUrl(token, endpoints.owgw);
if (endpoints.owprov) getProvUIUrl(token, endpoints.owprov);
setItem('gateway_endpoints', JSON.stringify(endpoints));
setEndpoints(endpoints);
setCurrentToken(token);
}
})
.catch((error) => {
if (formType === 'change-password') {
if (error.response?.data?.ErrorCode === 3) {
setChangeResponse({
text: t('login.previously_used'),
error: true,
tried: true,
});
} else if (error.response?.data?.ErrorCode === 5) {
setChangeResponse({
text: t('common.invalid_password'),
error: true,
tried: true,
});
} else {
setChangeResponse({
text: t('login.change_password_error'),
error: true,
tried: true,
});
}
} else if (error.response.status === 403) {
if (error.response?.data?.ErrorCode === 1) setFormType('change-password');
else if (error.response?.data?.ErrorCode === 2) {
setLoginResponse({
text: t('common.invalid_credentials'),
error: true,
tried: true,
});
} else {
setLoginResponse({
text: t('login.login_error'),
error: true,
tried: true,
});
}
} else {
setLoginResponse({
text: t('login.login_error'),
error: true,
tried: true,
});
}
})
.finally(() => {
setLoading(false);
});
};
const sendForgotPasswordEmail = () => {
setForgotResponse(initialResponseState);
@@ -446,6 +547,7 @@ const Login = () => {
toggleForgotPassword={toggleForgotPassword}
formType={formType}
onKeyDown={onKeyDown}
submitForm={submitForm}
sendForgotPasswordEmail={sendForgotPasswordEmail}
changePasswordResponse={changePasswordResponse}
cancelPasswordChange={cancelPasswordChange}

View File

@@ -20,6 +20,23 @@ const UserListPage = () => {
const [loading, setLoading] = useState(true);
const [deleteLoading, setDeleteLoading] = useState(false);
const [usersPerPage, setUsersPerPage] = useState(getItem('devicesPerPage') || '10');
const [policies, setPolicies] = useState({
passwordPolicy: '',
passwordPattern: '',
accessPolicy: '',
});
const getPasswordPolicy = () => {
axiosInstance
.post(`${endpoints.owsec}/api/v1/oauth2?requirements=true`, {})
.then((response) => {
const newPolicies = response.data;
newPolicies.accessPolicy = `${endpoints.owsec}${newPolicies.accessPolicy}`;
newPolicies.passwordPolicy = `${endpoints.owsec}${newPolicies.passwordPolicy}`;
setPolicies(response.data);
})
.catch(() => {});
};
const toggleCreateModal = () => {
setShowCreateModal(!showCreateModal);
@@ -180,6 +197,7 @@ const UserListPage = () => {
useEffect(() => {
getUsers();
getPasswordPolicy();
}, []);
useEffect(() => {
@@ -193,7 +211,7 @@ const UserListPage = () => {
<div>
<UserListTable
t={t}
users={usersToDisplay}
users={usersToDisplay.sort((a, b) => a.email > b.email)}
loading={loading}
usersPerPage={usersPerPage}
setUsersPerPage={updateUsersPerPage}
@@ -206,12 +224,18 @@ const UserListPage = () => {
toggleEdit={toggleEditModal}
refreshUsers={getUsers}
/>
<CreateUserModal show={showCreateModal} toggle={toggleCreateModal} getUsers={getUsers} />
<CreateUserModal
show={showCreateModal}
toggle={toggleCreateModal}
getUsers={getUsers}
policies={policies}
/>
<EditUserModal
show={showEditModal}
toggle={toggleEditModal}
userId={userToEdit}
getUsers={getUsers}
policies={policies}
/>
</div>
);

View File

@@ -20,10 +20,12 @@ axiosInstance.interceptors.response.use(
case 401:
break;
case 403:
localStorage.removeItem('access_token');
localStorage.removeItem('gateway_endpoints');
sessionStorage.clear();
window.location.href = '/';
if (error.response.data?.ErrorCode === 9) {
localStorage.removeItem('access_token');
localStorage.removeItem('gateway_endpoints');
sessionStorage.clear();
window.location.href = '/';
}
break;
default:
break;