diff --git a/src/main/java/com/openisle/controller/AuthController.java b/src/main/java/com/openisle/controller/AuthController.java index abbce9e42..5348b5a66 100644 --- a/src/main/java/com/openisle/controller/AuthController.java +++ b/src/main/java/com/openisle/controller/AuthController.java @@ -8,6 +8,7 @@ import lombok.Data; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.Map; @RestController @RequestMapping("/api/auth") @@ -25,9 +26,17 @@ public class AuthController { @PostMapping("/register") public ResponseEntity register(@RequestBody RegisterRequest req) { User user = userService.register(req.getUsername(), req.getEmail(), req.getPassword()); - emailService.sendEmail(user.getEmail(), "Welcome to OpenIsle", "Thank you for registering."); - String token = jwtService.generateToken(user.getUsername()); - return ResponseEntity.ok(new JwtResponse(token)); + emailService.sendEmail(user.getEmail(), "Verification Code", "Your verification code is " + user.getVerificationCode()); + return ResponseEntity.ok(Map.of("message", "Verification code sent")); + } + + @PostMapping("/verify") + public ResponseEntity verify(@RequestBody VerifyRequest req) { + boolean ok = userService.verifyCode(req.getUsername(), req.getCode()); + if (ok) { + return ResponseEntity.ok(Map.of("message", "Verified")); + } + return ResponseEntity.badRequest().body(Map.of("error", "Invalid verification code")); } /** @@ -39,7 +48,7 @@ public class AuthController { public ResponseEntity login(@RequestBody LoginRequest req) { return userService.authenticate(req.getUsername(), req.getPassword()) .map(user -> ResponseEntity.ok(new JwtResponse(jwtService.generateToken(user.getUsername())))) - .orElse(ResponseEntity.status(401).build()); + .orElse(ResponseEntity.status(401).body(Map.of("error", "Invalid credentials or user not verified"))); } @Data @@ -55,6 +64,12 @@ public class AuthController { private String password; } + @Data + private static class VerifyRequest { + private String username; + private String code; + } + @Data private static class JwtResponse { private final String token; diff --git a/src/main/java/com/openisle/controller/GlobalExceptionHandler.java b/src/main/java/com/openisle/controller/GlobalExceptionHandler.java new file mode 100644 index 000000000..dcbd83e34 --- /dev/null +++ b/src/main/java/com/openisle/controller/GlobalExceptionHandler.java @@ -0,0 +1,17 @@ +package com.openisle.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.Map; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception ex) { + return ResponseEntity.badRequest().body(Map.of("error", ex.getMessage())); + } +} + diff --git a/src/main/java/com/openisle/controller/HelloController.java b/src/main/java/com/openisle/controller/HelloController.java index 422031e3a..11c808fb2 100644 --- a/src/main/java/com/openisle/controller/HelloController.java +++ b/src/main/java/com/openisle/controller/HelloController.java @@ -2,6 +2,7 @@ package com.openisle.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.Map; @RestController public class HelloController { @@ -10,7 +11,7 @@ public class HelloController { * -H "Authorization: Bearer " */ @GetMapping("/api/hello") - public String hello() { - return "Hello, Authenticated User"; + public Map hello() { + return Map.of("message", "Hello, Authenticated User"); } } diff --git a/src/main/java/com/openisle/model/User.java b/src/main/java/com/openisle/model/User.java index b3d0c407b..ef2997d79 100644 --- a/src/main/java/com/openisle/model/User.java +++ b/src/main/java/com/openisle/model/User.java @@ -23,4 +23,9 @@ public class User { @Column(nullable = false) private String password; + + @Column(nullable = false) + private boolean verified = false; + + private String verificationCode; } diff --git a/src/main/java/com/openisle/service/UserService.java b/src/main/java/com/openisle/service/UserService.java index 3ec0bba60..b94af0c46 100644 --- a/src/main/java/com/openisle/service/UserService.java +++ b/src/main/java/com/openisle/service/UserService.java @@ -8,6 +8,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.Optional; +import java.util.Random; @Service @RequiredArgsConstructor @@ -17,17 +18,33 @@ public class UserService { public User register(String username, String email, String password) { if (userRepository.findByUsername(username).isPresent() || userRepository.findByEmail(email).isPresent()) { - throw new RuntimeException("User already exists"); + throw new IllegalStateException("User already exists"); } User user = new User(); user.setUsername(username); user.setEmail(email); user.setPassword(passwordEncoder.encode(password)); + user.setVerified(false); + String code = String.format("%06d", new Random().nextInt(1000000)); + user.setVerificationCode(code); return userRepository.save(user); } + public boolean verifyCode(String username, String code) { + Optional userOpt = userRepository.findByUsername(username); + if (userOpt.isPresent() && code.equals(userOpt.get().getVerificationCode())) { + User user = userOpt.get(); + user.setVerified(true); + user.setVerificationCode(null); + userRepository.save(user); + return true; + } + return false; + } + public Optional authenticate(String username, String password) { return userRepository.findByUsername(username) + .filter(User::isVerified) .filter(user -> passwordEncoder.matches(password, user.getPassword())); } }