Skip to content

Commit

Permalink
Change phone number feature (#268)
Browse files Browse the repository at this point in the history
* Added functionality to send otp for phone number change request


---------

Co-authored-by: Roshan Piyush <piyush.roshan@gmail.com>
  • Loading branch information
pushkarpawar15 and piyushroshan authored Aug 29, 2024
1 parent 9fe9ba7 commit 9a061c4
Show file tree
Hide file tree
Showing 42 changed files with 1,205 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ public class UserMessage {
"User registered successfully! Please Login.";
public static final String SIGN_UP_FAILED = "User registered failed! Please retry.";
public static final String NUMBER_ALREADY_REGISTERED = "Number already registered! Number: ";
public static final String NUMBER_NOT_REGISTERED = "Given Number is not registered! Number:";
public static final String CHANGE_PHONE_MESSAGE =
"The otp has been sent to your email. If you have used example.com email, check your email using the MailHog web portal.";
public static final String NUMBER_CHANGE_SUCCESSFUL = "Phone number change is successful";
public static final String NEW_NUMBER_DOES_NOT_BELONG =
"Fail, new number parameter doesn’t match with OTP";
public static final String OLD_NUMBER_DOES_NOT_BELONG =
"Fail, number parameter doesn’t belong to the user";
public static final String EMAIL_ALREADY_REGISTERED = "Email already registered! Email: ";
public static final String GIVEN_URL_ALREADY_USED =
"Given URL is already used! Please try to login..";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.crapi.controller;

import com.crapi.model.CRAPIResponse;
import com.crapi.model.ChangePhoneForm;
import com.crapi.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@CrossOrigin
@RestController
@RequestMapping("/identity/api")
public class ChangePhoneController {
@Autowired UserService userService;

/**
* @param changePhoneForm changePhoneForm contains old phone number and new phone number, api will
* send otp to email address.
* @param request getting jwt token for user from request header
* @return first check phone number is already registered or not if it is there then return phone
* number already registered then try with new phone number.
*/
@PostMapping("/v2/user/change-phone-number")
public ResponseEntity<CRAPIResponse> changesPhone(
@Valid @RequestBody ChangePhoneForm changePhoneForm, HttpServletRequest request) {
CRAPIResponse changePhoneResponse = userService.changePhoneRequest(request, changePhoneForm);
if (changePhoneResponse != null && changePhoneResponse.getStatus() == 403) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(changePhoneResponse);
} else if (changePhoneResponse != null && changePhoneResponse.getStatus() == 404) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(changePhoneResponse);
}
return ResponseEntity.status(HttpStatus.OK).body(changePhoneResponse);
}

/**
* @param changePhoneForm changeEmailForm contains old phone number and new phone number, with
* otp, this function will verify number and otp
* @param request getting jwt token for user from request header
* @return verify if otp is valid then it will update the user phone number
*/
@PostMapping("v2/user/verify-phone-otp")
public ResponseEntity<CRAPIResponse> verifyPhoneOTP(
@RequestBody ChangePhoneForm changePhoneForm, HttpServletRequest request) {
CRAPIResponse verifyPhoneOTPResponse = userService.verifyPhoneOTP(request, changePhoneForm);
if (verifyPhoneOTPResponse != null && verifyPhoneOTPResponse.getStatus() == 200) {
return ResponseEntity.status(HttpStatus.OK).body(verifyPhoneOTPResponse);
} else if (verifyPhoneOTPResponse != null && verifyPhoneOTPResponse.getStatus() == 404) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(verifyPhoneOTPResponse);
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(verifyPhoneOTPResponse);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.crapi.entity;

import com.crapi.enums.EStatus;
import jakarta.persistence.*;
import lombok.Data;

@Entity
@Table(name = "otp_phoneNumberChange")
@Data
public class ChangePhoneRequest {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

@Column(name = "new_phone")
private String newPhone;

@Column(name = "old_phone")
private String oldPhone;

@Column(name = "otp")
private String otp;

private String status;

@OneToOne private User user;

public ChangePhoneRequest() {}

public ChangePhoneRequest(String newPhone, String oldPhone, String otp, User user) {
this.newPhone = newPhone;
this.oldPhone = oldPhone;
this.otp = otp;
this.user = user;
this.status = EStatus.ACTIVE.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.crapi.model;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
public class ChangePhoneForm {
@NotBlank
@Size(max = 15)
private String old_number;

@NotBlank
@Size(max = 15)
private String new_number;

@Size(min = 3, max = 4)
private String otp;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.crapi.repository;

import com.crapi.entity.ChangePhoneRequest;
import com.crapi.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ChangePhoneRepository extends JpaRepository<ChangePhoneRequest, Long> {
ChangePhoneRequest findByUser(User user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ public class UserServiceImpl implements UserService {

@Autowired AuthenticationManager authenticationManager;

@Autowired ChangePhoneRepository changePhoneRepository;

public UserServiceImpl() {
setFactory(log4jContextFactory);
LOG4J_LOGGER = LogManager.getLogger(UserService.class);
Expand Down Expand Up @@ -471,4 +473,86 @@ public ApiKeyResponse generateApiKey(HttpServletRequest request) {
}
return new ApiKeyResponse("");
}

/**
* @param changePhoneForm contains old phone number and new phone number, api will send otp to
* change number to email address.
* @return send otp to email with random generated otp.
*/
@Transactional
@Override
public CRAPIResponse changePhoneRequest(
HttpServletRequest request, ChangePhoneForm changePhoneForm) {
String otp;
User user;
ChangePhoneRequest changePhoneRequest;
// checking if new phone in user login table if present then disallow
if (userRepository.existsByNumber(changePhoneForm.getNew_number())) {
return new CRAPIResponse(
UserMessage.NUMBER_ALREADY_REGISTERED + changePhoneForm.getNew_number(), 403);
}
// checking if old phone is registered or not
if (!userRepository.existsByNumber(changePhoneForm.getOld_number())) {
return new CRAPIResponse(
(UserMessage.NUMBER_NOT_REGISTERED) + changePhoneForm.getOld_number(), 404);
}

otp = OTPGenerator.generateRandom(4);
user = getUserFromToken(request);
// fetching change phone data for user
changePhoneRequest = changePhoneRepository.findByUser(user);
if (changePhoneRequest == null) {
// Creating new object if changePhone data for user in not in database
changePhoneRequest =
new ChangePhoneRequest(
changePhoneForm.getNew_number(), changePhoneForm.getOld_number(), otp, user);
} else {
// updating existing record
changePhoneRequest.setOtp(otp);
changePhoneRequest.setOldPhone(changePhoneForm.getOld_number());
changePhoneRequest.setNewPhone(changePhoneForm.getNew_number());
}
changePhoneForm.setOtp(otp);
changePhoneRepository.save(changePhoneRequest);
smtpMailServer.sendMail(
user.getEmail(),
MailBody.changeMailBody(changePhoneForm),
"crAPI: Change Phone Number OTP");

return new CRAPIResponse(
UserMessage.CHANGE_PHONE_MESSAGE + changePhoneForm.getNew_number(), 200);
}

/**
* @param request getting jwt token for user from request header
* @param changePhoneForm contains old phone number and new phone number, with otp, this function
* will verify phone number and otp
* @return it checks user token and verify with otp if user verify then correct then we will
* update email for user.
*/
@Transactional
@Override
public CRAPIResponse verifyPhoneOTP(HttpServletRequest request, ChangePhoneForm changePhoneForm) {
ChangePhoneRequest changePhoneRequest;
User user;
user = getUserFromToken(request);
changePhoneRequest = changePhoneRepository.findByUser(user);
if (changePhoneRequest != null) {
if (changePhoneForm.getOtp() != null
&& changePhoneForm.getOtp().equalsIgnoreCase(changePhoneRequest.getOtp())) {
if (changePhoneForm.getOld_number().equalsIgnoreCase((user.getNumber()))) {
if (changePhoneForm.getNew_number().equalsIgnoreCase(changePhoneRequest.getNewPhone())) {
user.setNumber(changePhoneRequest.getNewPhone());
userRepository.save(user);
return new CRAPIResponse(UserMessage.NUMBER_CHANGE_SUCCESSFUL, 200);
}
return new CRAPIResponse(UserMessage.NEW_NUMBER_DOES_NOT_BELONG, 500);
}
return new CRAPIResponse(UserMessage.OLD_NUMBER_DOES_NOT_BELONG, 500);
}
return new CRAPIResponse(UserMessage.INVALID_OTP, 500);
}

return new CRAPIResponse(UserMessage.INVALID_CREDENTIALS, 500);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@ CRAPIResponse resetPassword(LoginForm loginForm, HttpServletRequest request)

CRAPIResponse changeEmailRequest(HttpServletRequest request, ChangeEmailForm loginForm);

CRAPIResponse changePhoneRequest(HttpServletRequest request, ChangePhoneForm changePhoneForm);

CRAPIResponse verifyEmailToken(HttpServletRequest request, ChangeEmailForm changeEmailForm);

CRAPIResponse verifyPhoneOTP(HttpServletRequest request, ChangePhoneForm changePhoneForm);

User getUserFromToken(HttpServletRequest request);

User getUserFromTokenWithoutValidation(HttpServletRequest request);
Expand Down
34 changes: 33 additions & 1 deletion services/identity/src/main/java/com/crapi/utils/MailBody.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.crapi.entity.UserDetails;
import com.crapi.entity.VehicleDetails;
import com.crapi.model.ChangeEmailForm;
import com.crapi.model.ChangePhoneForm;

public class MailBody {

Expand Down Expand Up @@ -74,7 +75,7 @@ public static String signupMailBody(VehicleDetails vehicleDetails, String name)

/**
* @param changeEmailRequest
* @return Mail Body, for Chnage Email.
* @return Mail Body, for Change Email.
*/
public static String changeMailBody(ChangeEmailForm changeEmailRequest) {
String msgBody =
Expand Down Expand Up @@ -103,6 +104,37 @@ public static String changeMailBody(ChangeEmailForm changeEmailRequest) {
return msgBody;
}

/**
* @param changePhoneRequest
* @return Mail Body, for Change Phone number.
*/
public static String changeMailBody(ChangePhoneForm changePhoneRequest) {
String msgBody =
"<html><body>"
+ "<font face='calibri' style = 'font-size:15px; color:#000;'>Hi"
+ "<font>,"
+ "<p><font face='calibri' style = 'font-size:15px;color:#000;'>We received a request to change your account phone Number. The previous number is: </font><font face='calibri' font color='#0000ff'><b>"
+ changePhoneRequest.getOld_number()
+ "</b></font>"
+ "<font face='calibri' style = 'font-size:15px;color:#000;'> and the new one is: <b>"
+ changePhoneRequest.getNew_number()
+ "</b></font></p>"
+ "<font face='calibri' style = 'font-size:15px;color:#000;'>To complete the process, please use the following otp: <b>"
+ changePhoneRequest.getOtp()
+ "</b>"
+ "<br>"
+ "<br>"
+ "<p><font face='calibri' style = 'font-size:15px;color:#000;'>If you haven not sent a request to change your phone number, please ignore this message.</font></p>"
+ "<p><font face='calibri' style = 'font-size:15px;color:#000;'>Thank You & have a wonderful day !</font></p>"
+ "<font face='calibri' style = 'font-size:15px;color:#000;'>Warm Regards,<br/><b>crAPI - Team</b></font><font face='calibri' font color='#0000ff'></font><br/>"
+ "<strong>Email:</strong>&nbsp;<a href='mailto:support@crapi.io'>support@crapi.io</a></font><br><font face='calibri'>&nbsp;&nbsp;<br> "
+ "<em style= 'color:#000;'>This E-mail and any attachments are private, intended solely for the use of the addressee. If you are not the intended recipient, they have been sent to you in error: any use of information in them is strictly prohibited. </em>"
+ "</body>"
+ "</html>";

return msgBody;
}

/**
* @param code
* @param email
Expand Down
Loading

0 comments on commit 9a061c4

Please sign in to comment.