diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/security/auth/BasicAuthenticator.java b/openmetadata-service/src/main/java/org/openmetadata/service/security/auth/BasicAuthenticator.java index 2b4711d8b75a..1329be62b5b9 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/security/auth/BasicAuthenticator.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/security/auth/BasicAuthenticator.java @@ -16,7 +16,6 @@ import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import static javax.ws.rs.core.Response.Status.NOT_IMPLEMENTED; -import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; import static org.openmetadata.schema.api.teams.CreateUser.CreatePasswordType.ADMIN_CREATE; import static org.openmetadata.schema.auth.ChangePasswordRequest.RequestType.SELF; import static org.openmetadata.schema.auth.ChangePasswordRequest.RequestType.USER; @@ -271,7 +270,7 @@ public void changeUserPwdWithOldPwd(UriInfo uriInfo, String userName, ChangePass if (request.getRequestType() == SELF && !BCrypt.verifyer().verify(request.getOldPassword().toCharArray(), storedHashPassword).verified) { - throw new CustomExceptionMessage(UNAUTHORIZED, "Old Password is not correct"); + throw new CustomExceptionMessage(BAD_REQUEST, "Old Password is not correct"); } storedBasicAuthMechanism.setPassword(newHashedPassword); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.test.tsx new file mode 100644 index 000000000000..99dc6a9ce96d --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.test.tsx @@ -0,0 +1,144 @@ +/* + * Copyright 2023 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { act, fireEvent, render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import ChangePasswordForm from './ChangePasswordForm'; + +const mockSave = jest.fn(); + +const mockCancel = jest.fn(); + +const MOCK_PROPS = { + visible: true, + onCancel: mockCancel, + isLoggedInUser: true, + isLoading: false, + onSave: mockSave, +}; + +describe('ChangePasswordForm', () => { + it('should render correctly', async () => { + render(); + const modal = await screen.findByTestId('modal-container'); + + expect(modal).toBeInTheDocument(); + }); + + it('should handle form submission correctly for logged in user', async () => { + render(); + const cancelButton = await screen.findByText('Cancel'); + const submitButton = await screen.findByText('label.update-entity'); + + expect(cancelButton).toBeInTheDocument(); + expect(submitButton).toBeInTheDocument(); + + userEvent.type( + await screen.findByTestId('input-oldPassword'), + 'oldPassword' + ); + + userEvent.type(await screen.findByTestId('input-newPassword'), 'Test@123'); + userEvent.type( + await screen.findByTestId('input-confirm-newPassword'), + 'Test@123' + ); + + await act(async () => { + fireEvent.click(submitButton); + }); + + expect(mockSave).toHaveBeenCalledTimes(1); + }); + + it('handles form submission correctly for admin', async () => { + render( + + ); + + const cancelButton = await screen.findByText('Cancel'); + const submitButton = await screen.findByText('label.update-entity'); + + expect(cancelButton).toBeInTheDocument(); + expect(submitButton).toBeInTheDocument(); + + userEvent.type(await screen.findByTestId('input-newPassword'), 'Test@123'); + userEvent.type( + await screen.findByTestId('input-confirm-newPassword'), + 'Test@123' + ); + + await act(async () => { + fireEvent.click(submitButton); + }); + + expect(mockSave).toHaveBeenCalledWith({ + newPassword: 'Test@123', + confirmPassword: 'Test@123', + }); + }); + + it('should invoke onCancel when Cancel button is clicked', async () => { + render( + + ); + + const cancelButton = await screen.findByText('Cancel'); + const submitButton = await screen.findByText('label.update-entity'); + + expect(cancelButton).toBeInTheDocument(); + expect(submitButton).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(cancelButton); + }); + + expect(mockCancel).toHaveBeenCalledTimes(1); + }); + + it('displays loading state during submission', async () => { + render(); + const submitButton = await screen.findByText('label.update-entity'); + + userEvent.type( + await screen.findByTestId('input-oldPassword'), + 'oldPassword' + ); + + userEvent.type(await screen.findByTestId('input-newPassword'), 'Test@123'); + userEvent.type( + await screen.findByTestId('input-confirm-newPassword'), + 'Test@123' + ); + + await act(async () => { + fireEvent.click(submitButton); + }); + + expect( + await screen.findByRole('img', { name: 'loading' }) + ).toBeInTheDocument(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.tsx index e16a2ee688c7..0f66127755bf 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.tsx @@ -42,6 +42,7 @@ const ChangePasswordForm: React.FC = ({ centered closable={false} confirmLoading={isLoading} + data-testid="modal-container" maskClosable={false} okButtonProps={{ form: 'change-password-form', @@ -67,6 +68,7 @@ const ChangePasswordForm: React.FC = ({ onFinish={onSave}> {isLoggedInUser && ( = ({ ]}> = ({ ]}> = ({ ]}> diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Users/UsersProfile/UserProfileDetails/UserProfileDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Users/UsersProfile/UserProfileDetails/UserProfileDetails.component.tsx index 744a1c81a4ca..5d8cb88c7283 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Users/UsersProfile/UserProfileDetails/UserProfileDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Users/UsersProfile/UserProfileDetails/UserProfileDetails.component.tsx @@ -171,27 +171,31 @@ const UserProfileDetails = ({ ), [showChangePasswordComponent] ); - const handleChangePassword = async (data: ChangePasswordRequest) => { try { setIsLoading(true); + + const newData = { + username: userData.name, + requestType: isLoggedInUser ? RequestType.Self : RequestType.User, + }; + const sendData = { ...data, - ...(isAdminUser && - !isLoggedInUser && { - username: userData.name, - requestType: RequestType.User, - }), + ...newData, }; + await changePassword(sendData); - setIsChangePassword(false); + showSuccessToast( t('server.update-entity-success', { entity: t('label.password') }) ); - } catch (err) { - showErrorToast(err as AxiosError); + + setIsChangePassword(false); + } catch (error) { + showErrorToast(error as AxiosError); } finally { - setIsLoading(true); + setIsLoading(false); } };