diff --git a/src/main/java/org/ays/auth/service/impl/AysUserPasswordServiceImpl.java b/src/main/java/org/ays/auth/service/impl/AysUserPasswordServiceImpl.java index adf91a9a3..70e5de1e9 100644 --- a/src/main/java/org/ays/auth/service/impl/AysUserPasswordServiceImpl.java +++ b/src/main/java/org/ays/auth/service/impl/AysUserPasswordServiceImpl.java @@ -39,16 +39,14 @@ class AysUserPasswordServiceImpl implements AysUserPasswordService { /** - * Handles the forgot password request by sending an email to the user - * with instructions to create a new password. + * Handles the forgot password request by sending an email to the user with instructions to create a new password. *

- * This method checks if a user exists with the provided email address. - * If the user exists and has no password set, a new temp password is generated. - * If the user already has a password, the forgot password timestamp is updated. - * In both cases, an email is sent to the user with instructions to create a new password. + * This method checks if the user exists based on the provided email address. If the user is found, + * it sets or updates the user's password with a temporary value and the current time as the forgotten password timestamp. + * An email is then sent to the user with instructions to create a new password. * - * @param forgotPasswordRequest The request containing the user's email address. - * @throws AysEmailAddressNotValidException if no user is found with the provided email address. + * @param forgotPasswordRequest the request containing the user's email address. + * @throws AysEmailAddressNotValidException if the email address does not correspond to any existing user. */ @Override public void forgotPassword(final AysPasswordForgotRequest forgotPasswordRequest) { @@ -57,11 +55,16 @@ public void forgotPassword(final AysPasswordForgotRequest forgotPasswordRequest) final AysUser user = userReadPort.findByEmailAddress(emailAddress) .orElseThrow(() -> new AysEmailAddressNotValidException(emailAddress)); - final AysUser.Password password = AysUser.Password.builder() - .value(AysRandomUtil.generateUUID()) - .forgotAt(LocalDateTime.now()) - .build(); - user.setPassword(password); + final var passwordBuilder = AysUser.Password.builder() + .forgotAt(LocalDateTime.now()); + + if (user.getPassword() != null) { + passwordBuilder.value(user.getPassword().getValue()); + } else { + passwordBuilder.value(AysRandomUtil.generateText(15)); + } + + user.setPassword(passwordBuilder.build()); final AysUser savedUser = userSavePort.save(user); userMailService.sendPasswordCreateEmail(savedUser); diff --git a/src/test/java/org/ays/auth/controller/AysAuthEndToEndTest.java b/src/test/java/org/ays/auth/controller/AysAuthEndToEndTest.java index af6251025..9387c2052 100644 --- a/src/test/java/org/ays/auth/controller/AysAuthEndToEndTest.java +++ b/src/test/java/org/ays/auth/controller/AysAuthEndToEndTest.java @@ -132,7 +132,7 @@ void givenValidAysTokenInvalidateRequest_whenTokensInvalidated_thenReturnSuccess @Test - void givenValidForgotPasswordRequest_whenNewPasswordCreatedAndPasswordCreateMailSent_thenReturnSuccessResponse() throws Exception { + void givenValidForgotPasswordRequest_whenUserHasNotPasswordAndPasswordCreatedWithLatestValueAndPasswordCreateMailSent_thenReturnSuccessResponse() throws Exception { // Initialize Institution institution = new InstitutionBuilder() @@ -186,6 +186,68 @@ void givenValidForgotPasswordRequest_whenNewPasswordCreatedAndPasswordCreateMail Assertions.assertNull(passwordFromDatabase.getUpdatedAt()); } + @Test + void givenValidForgotPasswordRequest_whenUserHasPasswordAndPasswordCreatedWithLatestValueAndPasswordCreateMailSent_thenReturnSuccessResponse() throws Exception { + + // Initialize + Institution institution = new InstitutionBuilder() + .withId(AysValidTestData.Admin.INSTITUTION_ID) + .build(); + + AysRole role = roleReadPort.findAllActivesByInstitutionId(institution.getId()) + .stream() + .findFirst() + .orElseThrow(); + + AysUser.Password password = new AysUserBuilder.PasswordBuilder() + .withValidValues() + .withoutId() + .build(); + + AysUser user = userSavePort.save( + new AysUserBuilder() + .withValidValues() + .withoutId() + .withRoles(List.of(role)) + .withInstitution(institution) + .withPassword(password) + .build() + ); + + // Given + AysPasswordForgotRequest mockForgotPasswordRequest = new AysForgotPasswordRequestBuilder() + .withEmailAddress(user.getEmailAddress()) + .build(); + + // Then + String endpoint = BASE_PATH.concat("/password/forgot"); + MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders + .post(endpoint, mockForgotPasswordRequest); + + AysResponse mockResponse = AysResponseBuilder.SUCCESS; + + aysMockMvc.perform(mockHttpServletRequestBuilder, mockResponse) + .andExpect(AysMockResultMatchersBuilders.status() + .isOk()) + .andExpect(AysMockResultMatchersBuilders.response() + .doesNotExist()); + + // Verify + AysUser userFromDatabase = userReadPort.findById(user.getId()) + .orElseThrow(); + + AysUser.Password passwordFromDatabase = userFromDatabase.getPassword(); + Assertions.assertNotNull(passwordFromDatabase); + Assertions.assertNotNull(passwordFromDatabase.getValue()); + Assertions.assertEquals(password.getValue(), passwordFromDatabase.getValue()); + Assertions.assertNotNull(passwordFromDatabase.getForgotAt()); + Assertions.assertTrue(passwordFromDatabase.getForgotAt().isAfter(LocalDateTime.now().minusMinutes(1))); + Assertions.assertNotNull(passwordFromDatabase.getCreatedUser()); + Assertions.assertNotNull(passwordFromDatabase.getCreatedAt()); + Assertions.assertNull(passwordFromDatabase.getUpdatedUser()); + Assertions.assertNull(passwordFromDatabase.getUpdatedAt()); + } + @Test void givenValidId_whenCheckPasswordIdSuccessfully_thenReturnSuccessResponse() throws Exception { diff --git a/src/test/java/org/ays/auth/service/impl/AysUserPasswordServiceImplTest.java b/src/test/java/org/ays/auth/service/impl/AysUserPasswordServiceImplTest.java index eebfedc73..741fc759f 100644 --- a/src/test/java/org/ays/auth/service/impl/AysUserPasswordServiceImplTest.java +++ b/src/test/java/org/ays/auth/service/impl/AysUserPasswordServiceImplTest.java @@ -13,6 +13,7 @@ import org.ays.auth.util.exception.AysEmailAddressNotValidException; import org.ays.auth.util.exception.AysUserPasswordCannotChangedException; import org.ays.auth.util.exception.AysUserPasswordDoesNotExistException; +import org.ays.common.util.AysRandomUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -49,17 +50,20 @@ void givenValidForgotPasswordRequest_whenUserExistWithPassword_thenSetPasswordFo .build(); // When + AysUser.Password password = new AysUserBuilder.PasswordBuilder() + .withValidValues() + .build(); AysUser mockUser = new AysUserBuilder() .withValidValues() .withEmailAddress(mockForgotPasswordRequest.getEmailAddress()) - .withPassword(new AysUserBuilder.PasswordBuilder().withValidValues().build()) + .withPassword(password) .build(); Mockito.when(userReadPort.findByEmailAddress(Mockito.anyString())) .thenReturn(Optional.of(mockUser)); AysUser.Password mockPassword = new AysUserBuilder.PasswordBuilder() .withValidValues() - .withValue("16b6a38b-a84d-4545-b05b-68758f998cb4") + .withValue(password.getValue()) .withForgotAt(LocalDateTime.now()) .build(); AysUser mockSavedUser = new AysUserBuilder() @@ -107,7 +111,7 @@ void givenValidForgotPasswordRequest_whenUserExistWithoutPassword_thenCreateTemp AysUser.Password mockPassword = new AysUserBuilder.PasswordBuilder() .withValidValues() - .withValue("b78a9229-9ca6-4a2b-9c14-aac160473d13") + .withValue(AysRandomUtil.generateText(15)) .withForgotAt(LocalDateTime.now()) .build(); AysUser mockSavedUser = new AysUserBuilder()