Google Sign in added
This commit is contained in:
@@ -44,6 +44,8 @@ public class SecurityConfig {
|
||||
.requestMatchers(HttpMethod.POST, "/api/auth/check").permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/api/auth/register").permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/api/auth/login").permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/api/auth/firebase-login").permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/api/auth/check-email").permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/api/auth/logout").permitAll()
|
||||
|
||||
// ── PUBLIC: Real-time stock updates (SSE — read-only, ordering app listens) ──
|
||||
|
||||
@@ -126,6 +126,40 @@ public class UserController {
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/check-email")
|
||||
public ResponseEntity<?> checkEmailExists(@RequestBody Map<String, String> body) {
|
||||
String email = body.get("email");
|
||||
if (email == null || email.trim().isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("error", "Email is required"));
|
||||
}
|
||||
boolean exists = userService.existsByEmail(email);
|
||||
return ResponseEntity.ok(Map.of("exists", exists));
|
||||
}
|
||||
|
||||
@PostMapping("/firebase-login")
|
||||
public ResponseEntity<?> firebaseLogin(@RequestBody Map<String, String> body) {
|
||||
String email = body.get("email");
|
||||
String name = body.get("name");
|
||||
String mobileNumber = body.get("mobileNumber"); // optional, supplied on first login
|
||||
|
||||
if (email == null || email.trim().isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("error", "Email is required"));
|
||||
}
|
||||
|
||||
LoginResponse response = userService.firebaseLoginOrCreate(email, name, mobileNumber);
|
||||
if (response.isSuccess()) {
|
||||
Long userId = response.getUser() != null ? response.getUser().getId() : null;
|
||||
String userMobile = response.getUser() != null ? response.getUser().getMobileNumber() : "";
|
||||
if (userId != null) {
|
||||
String token = jwtUtil.generateUserToken(userId, userMobile);
|
||||
response.setToken(token);
|
||||
}
|
||||
return ResponseEntity.ok(response);
|
||||
} else {
|
||||
return ResponseEntity.badRequest().body(response);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
public ResponseEntity<LoginResponse> logout(@Valid @RequestBody LoginRequest request) {
|
||||
LoginResponse response = userService.logout(request.getMobileNumber());
|
||||
|
||||
@@ -49,6 +49,7 @@ public class LoginResponse {
|
||||
private boolean isLoggedIn;
|
||||
private boolean isSuspended;
|
||||
private java.math.BigDecimal ritzTokenBalance;
|
||||
private String membership;
|
||||
|
||||
public UserDto() {}
|
||||
|
||||
@@ -61,6 +62,16 @@ public class LoginResponse {
|
||||
this.ritzTokenBalance = ritzTokenBalance;
|
||||
}
|
||||
|
||||
public UserDto(Long id, String mobileNumber, String name, boolean isLoggedIn, boolean isSuspended, java.math.BigDecimal ritzTokenBalance, String membership) {
|
||||
this.id = id;
|
||||
this.mobileNumber = mobileNumber;
|
||||
this.name = name;
|
||||
this.isLoggedIn = isLoggedIn;
|
||||
this.isSuspended = isSuspended;
|
||||
this.ritzTokenBalance = ritzTokenBalance;
|
||||
this.membership = membership;
|
||||
}
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
@@ -74,9 +85,12 @@ public class LoginResponse {
|
||||
public void setLoggedIn(boolean loggedIn) { this.isLoggedIn = loggedIn; }
|
||||
|
||||
public boolean isSuspended() { return isSuspended; }
|
||||
public void setSuspended(boolean suspended) { isSuspended = suspended; }
|
||||
public void setSuspended(boolean suspended) { this.isSuspended = suspended; }
|
||||
|
||||
public java.math.BigDecimal getRitzTokenBalance() { return ritzTokenBalance; }
|
||||
public void setRitzTokenBalance(java.math.BigDecimal ritzTokenBalance) { this.ritzTokenBalance = ritzTokenBalance; }
|
||||
|
||||
public String getMembership() { return membership; }
|
||||
public void setMembership(String membership) { this.membership = membership; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@ public class User {
|
||||
@Column(nullable = false, columnDefinition = "boolean default false")
|
||||
private boolean isSuspended = false;
|
||||
|
||||
@Column(unique = true, nullable = true)
|
||||
private String email;
|
||||
|
||||
@Column(nullable = true)
|
||||
private String membership;
|
||||
|
||||
@Column(nullable = true)
|
||||
private LocalDateTime lastLoginAt;
|
||||
|
||||
@@ -75,6 +81,12 @@ public class User {
|
||||
public LocalDateTime getLastLoginAt() { return lastLoginAt; }
|
||||
public void setLastLoginAt(LocalDateTime lastLoginAt) { this.lastLoginAt = lastLoginAt; }
|
||||
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
|
||||
public String getMembership() { return membership; }
|
||||
public void setMembership(String membership) { this.membership = membership; }
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
|
||||
@@ -11,6 +11,8 @@ import java.util.Optional;
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
Optional<User> findByMobileNumber(String mobileNumber);
|
||||
boolean existsByMobileNumber(String mobileNumber);
|
||||
Optional<User> findByEmail(String email);
|
||||
boolean existsByEmail(String email);
|
||||
|
||||
@Query("SELECT u FROM User u WHERE LOWER(u.name) LIKE LOWER(CONCAT('%', :search, '%')) " +
|
||||
"OR u.mobileNumber LIKE CONCAT('%', :search, '%')")
|
||||
|
||||
@@ -61,7 +61,7 @@ public class UserService {
|
||||
userRepository.save(user);
|
||||
|
||||
LoginResponse.UserDto userDto = new LoginResponse.UserDto(
|
||||
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance()
|
||||
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance(), user.getMembership()
|
||||
);
|
||||
|
||||
return new LoginResponse(true, "Registration successful. You are now logged in.", userDto);
|
||||
@@ -81,7 +81,7 @@ public class UserService {
|
||||
|
||||
if (user.isSuspended()) {
|
||||
LoginResponse.UserDto userDto = new LoginResponse.UserDto(
|
||||
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance()
|
||||
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance(), user.getMembership()
|
||||
);
|
||||
return new LoginResponse(false, "Your account has been suspended. Please contact the administrator.", userDto);
|
||||
}
|
||||
@@ -95,7 +95,7 @@ public class UserService {
|
||||
userRepository.save(user);
|
||||
|
||||
LoginResponse.UserDto userDto = new LoginResponse.UserDto(
|
||||
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance()
|
||||
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance(), user.getMembership()
|
||||
);
|
||||
|
||||
return new LoginResponse(true, "Login successful.", userDto);
|
||||
@@ -161,7 +161,7 @@ public class UserService {
|
||||
return null;
|
||||
}
|
||||
User user = userOpt.get();
|
||||
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance());
|
||||
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance(), user.getMembership());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +181,8 @@ public class UserService {
|
||||
user.getName(),
|
||||
user.isLoggedIn(),
|
||||
user.isSuspended(),
|
||||
user.getRitzTokenBalance()
|
||||
user.getRitzTokenBalance(),
|
||||
user.getMembership()
|
||||
));
|
||||
}
|
||||
|
||||
@@ -220,7 +221,7 @@ public class UserService {
|
||||
}
|
||||
|
||||
userRepository.save(user);
|
||||
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance());
|
||||
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance(), user.getMembership());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,7 +242,7 @@ public class UserService {
|
||||
}
|
||||
|
||||
userRepository.save(user);
|
||||
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance());
|
||||
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance(), user.getMembership());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,5 +265,60 @@ public class UserService {
|
||||
public void deleteUser(Long userId) {
|
||||
userRepository.deleteById(userId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate or create a customer user via Firebase/Google login.
|
||||
*/
|
||||
public boolean existsByEmail(String email) {
|
||||
if (email == null) return false;
|
||||
return userRepository.existsByEmail(email.trim().toLowerCase());
|
||||
}
|
||||
|
||||
public LoginResponse firebaseLoginOrCreate(String email, String name, String mobileNumber) {
|
||||
if (email == null || email.isBlank()) {
|
||||
return new LoginResponse(false, "Email is required for Google authentication.");
|
||||
}
|
||||
|
||||
String cleanEmail = email.trim().toLowerCase();
|
||||
String finalName = name != null ? name : "Google User";
|
||||
String membership = "Member"; // Everyone is classified as a normal Member now
|
||||
|
||||
Optional<User> userOpt = userRepository.findByEmail(cleanEmail);
|
||||
User user;
|
||||
|
||||
if (userOpt.isPresent()) {
|
||||
user = userOpt.get();
|
||||
if (user.isSuspended()) {
|
||||
return new LoginResponse(false, "Your account has been suspended. Please contact the administrator.");
|
||||
}
|
||||
user.setName(finalName);
|
||||
user.setMembership(membership);
|
||||
user.setLoggedIn(true);
|
||||
user.setLastLoginAt(LocalDateTime.now());
|
||||
userRepository.save(user);
|
||||
} else {
|
||||
if (mobileNumber == null || !mobileNumber.matches("^[0-9]{10}$")) {
|
||||
return new LoginResponse(false, "A valid 10-digit mobile number is required for first-time registration.");
|
||||
}
|
||||
if (userRepository.existsByMobileNumber(mobileNumber)) {
|
||||
return new LoginResponse(false, "This mobile number is already registered to another account.");
|
||||
}
|
||||
|
||||
user = new User();
|
||||
user.setEmail(cleanEmail);
|
||||
user.setName(finalName);
|
||||
user.setMembership(membership);
|
||||
user.setMobileNumber(mobileNumber);
|
||||
user.setPinHash(passwordEncoder.encode(java.util.UUID.randomUUID().toString()));
|
||||
user.setLoggedIn(true);
|
||||
user.setLastLoginAt(LocalDateTime.now());
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
LoginResponse.UserDto userDto = new LoginResponse.UserDto(
|
||||
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance(), user.getMembership()
|
||||
);
|
||||
|
||||
return new LoginResponse(true, "Login successful.", userDto);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user