Skip to content

Commit

Permalink
AYS-328 | Forgot Password Flow Has Been Fixed (#360)
Browse files Browse the repository at this point in the history
  • Loading branch information
agitrubard authored Aug 6, 2024
1 parent b36f181 commit 3b86250
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
* <p>
* 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) {
Expand All @@ -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);
Expand Down
64 changes: 63 additions & 1 deletion src/test/java/org/ays/auth/controller/AysAuthEndToEndTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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<Void> 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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit 3b86250

Please sign in to comment.