Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change phone number feature #268

Merged
merged 13 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading