diff --git a/app/backend/pom.xml b/app/backend/pom.xml
index ceb91d70..a0459ca4 100644
--- a/app/backend/pom.xml
+++ b/app/backend/pom.xml
@@ -52,6 +52,10 @@
spring-boot-starter-test
test
+
+ org.springframework.boot
+ spring-boot-starter-mail
+
io.jsonwebtoken
jjwt
diff --git a/app/backend/src/main/java/com/app/gamereview/controller/AuthController.java b/app/backend/src/main/java/com/app/gamereview/controller/AuthController.java
index d3b32aea..7b0c18a1 100644
--- a/app/backend/src/main/java/com/app/gamereview/controller/AuthController.java
+++ b/app/backend/src/main/java/com/app/gamereview/controller/AuthController.java
@@ -3,15 +3,23 @@
import com.app.gamereview.dto.request.LoginUserRequestDto;
import com.app.gamereview.dto.request.ChangeUserPasswordRequestDto;
import com.app.gamereview.dto.request.RegisterUserRequestDto;
+import com.app.gamereview.dto.request.VerifyResetCodeRequestDto;
import com.app.gamereview.dto.response.LoginUserResponseDto;
+import com.app.gamereview.model.ResetCode;
import com.app.gamereview.model.User;
+import com.app.gamereview.repository.ResetCodeRepository;
import com.app.gamereview.service.AuthService;
+import com.app.gamereview.service.EmailService;
+import com.app.gamereview.service.UserService;
import com.app.gamereview.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
+import java.util.Date;
import java.util.Optional;
+import java.util.UUID;
@RestController
@RequestMapping("/api/auth")
@@ -19,14 +27,21 @@ public class AuthController {
private final AuthService authService;
+ private final EmailService emailService;
+
+ private final UserService userService;
+
+ private final ResetCodeRepository resetCodeRepository;
+
@Autowired
- public AuthController(AuthService authService) {
+ public AuthController(AuthService authService, EmailService emailService, UserService userService,
+ ResetCodeRepository resetCodeRepository) {
this.authService = authService;
+ this.emailService = emailService;
+ this.userService = userService;
+ this.resetCodeRepository = resetCodeRepository;
}
- @Autowired
- private JwtUtil jwtUtil;
-
@PostMapping("/register")
public ResponseEntity registerUser(@RequestBody RegisterUserRequestDto registerUserRequestDto) {
User userToCreate = authService.registerUser(registerUserRequestDto);
@@ -45,4 +60,66 @@ public ResponseEntity login(@RequestBody LoginUserRequestD
return ResponseEntity.ok(loginResponse);
}
+ @PostMapping("/forgot-password")
+ public ResponseEntity forgotPassword(@RequestParam String email) {
+ User user = userService.getUserByEmail(email);
+
+ if (user == null) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found");
+ }
+
+ // Generate and save a reset code (you can use UUID or any secure method)
+ String code = generateResetCode(user.getId());
+
+ // Send email with reset code
+ String subject = "Password Reset";
+ String message = "Your password reset code is: " + code;
+ message += "\n The reset code will expire after 24 hours.";
+ emailService.sendEmail(email, subject, message);
+
+ return ResponseEntity.ok("Reset code sent successfully");
+ }
+
+ @PostMapping("/verify-reset-code")
+ public ResponseEntity verifyResetCode(@RequestBody VerifyResetCodeRequestDto request) {
+ Optional resetCodeOptional = resetCodeRepository.findByCode(request.getResetCode());
+ if (resetCodeOptional.isEmpty() || resetCodeOptional.get().getExpirationDate().before(new Date())) {
+ // Invalid or expired reset code
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid or expired reset code");
+ }
+
+ ResetCode resetCode = resetCodeOptional.get();
+
+ // Check if the reset code matches the user
+ String userEmail = userService.getUserById(resetCode.getUserId()).getEmail();
+ if (!userEmail.equals(request.getUserEmail())) {
+ // Reset code does not match the user
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(userEmail + " " + request.getUserEmail());
+ }
+
+ // Reset code is valid, generate a JWT token for the user
+ String token = JwtUtil.generateToken(userService.getUserById(resetCode.getUserId()).getEmail());
+
+ // Clear the reset code after generating the token
+ resetCodeRepository.deleteByUserId(resetCode.getUserId());
+
+ return ResponseEntity.ok(token);
+ }
+
+ private String generateResetCode(String userId) {
+ // Check if a reset code exists for the user
+ ResetCode existingResetCode = resetCodeRepository.findByUserId(userId);
+
+ // If a reset code exists, delete it
+ if (existingResetCode != null) {
+ resetCodeRepository.delete(existingResetCode);
+ }
+ String code = UUID.randomUUID().toString().replace("-", "").substring(0, 6).toUpperCase();
+
+ ResetCode resetCode = new ResetCode(code, userId, new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000));
+ resetCodeRepository.save(resetCode);
+
+ return code;
+ }
+
}
diff --git a/app/backend/src/main/java/com/app/gamereview/dto/request/VerifyResetCodeRequestDto.java b/app/backend/src/main/java/com/app/gamereview/dto/request/VerifyResetCodeRequestDto.java
new file mode 100644
index 00000000..12252c08
--- /dev/null
+++ b/app/backend/src/main/java/com/app/gamereview/dto/request/VerifyResetCodeRequestDto.java
@@ -0,0 +1,12 @@
+package com.app.gamereview.dto.request;
+
+import lombok.Getter;
+
+@Getter
+public class VerifyResetCodeRequestDto {
+
+ private String resetCode;
+
+ private String userEmail;
+
+}
\ No newline at end of file
diff --git a/app/backend/src/main/java/com/app/gamereview/model/ResetCode.java b/app/backend/src/main/java/com/app/gamereview/model/ResetCode.java
new file mode 100644
index 00000000..7128d171
--- /dev/null
+++ b/app/backend/src/main/java/com/app/gamereview/model/ResetCode.java
@@ -0,0 +1,60 @@
+package com.app.gamereview.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+import java.util.Date;
+
+@Document(collection = "resetCodes")
+public class ResetCode {
+
+ @Id
+ private String id;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUser(String userId) {
+ this.userId = userId;
+ }
+
+ public Date getExpirationDate() {
+ return expirationDate;
+ }
+
+ public void setExpirationDate(Date expirationDate) {
+ this.expirationDate = expirationDate;
+ }
+
+ private String code;
+
+ @Indexed(unique = true) // Ensures a unique constraint on userId field
+ private String userId; // ID of the associated user
+
+ private Date expirationDate;
+
+ public ResetCode(String code, String userId, Date expirationDate) {
+
+ this.code = code;
+ this.userId = userId;
+ this.expirationDate = expirationDate;
+ }
+
+}
diff --git a/app/backend/src/main/java/com/app/gamereview/repository/ResetCodeRepository.java b/app/backend/src/main/java/com/app/gamereview/repository/ResetCodeRepository.java
new file mode 100644
index 00000000..37c30813
--- /dev/null
+++ b/app/backend/src/main/java/com/app/gamereview/repository/ResetCodeRepository.java
@@ -0,0 +1,16 @@
+package com.app.gamereview.repository;
+
+import com.app.gamereview.model.ResetCode;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+import java.util.Optional;
+
+public interface ResetCodeRepository extends MongoRepository {
+
+ ResetCode findByUserId(String userId);
+
+ Optional findByCode(String code);
+
+ void deleteByUserId(String userId);
+
+}
\ No newline at end of file
diff --git a/app/backend/src/main/java/com/app/gamereview/repository/UserRepository.java b/app/backend/src/main/java/com/app/gamereview/repository/UserRepository.java
index a0a22c8f..a9786afa 100644
--- a/app/backend/src/main/java/com/app/gamereview/repository/UserRepository.java
+++ b/app/backend/src/main/java/com/app/gamereview/repository/UserRepository.java
@@ -2,6 +2,7 @@
import com.app.gamereview.model.User;
import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.Query;
import java.util.List;
import java.util.Optional;
@@ -13,4 +14,7 @@ public interface UserRepository extends MongoRepository {
Optional findByEmailAndIsDeletedFalse(String email);
+ @Query("{ 'email' : ?0 }")
+ Optional findByEmail(String email);
+
}
diff --git a/app/backend/src/main/java/com/app/gamereview/service/EmailService.java b/app/backend/src/main/java/com/app/gamereview/service/EmailService.java
new file mode 100644
index 00000000..127a1f03
--- /dev/null
+++ b/app/backend/src/main/java/com/app/gamereview/service/EmailService.java
@@ -0,0 +1,25 @@
+package com.app.gamereview.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.stereotype.Service;
+
+@Service
+public class EmailService {
+
+ @Autowired
+ private JavaMailSender mailSender;
+
+ public void sendEmail(String toEmail, String subject, String body) {
+ SimpleMailMessage message = new SimpleMailMessage();
+ message.setFrom("bounswe2023.group5@gmail.com");
+ message.setTo(toEmail);
+ message.setText(body);
+ message.setSubject(subject);
+ mailSender.send(message);
+ System.out.println("Mail Send...");
+
+ }
+
+}
diff --git a/app/backend/src/main/java/com/app/gamereview/service/UserService.java b/app/backend/src/main/java/com/app/gamereview/service/UserService.java
index 7a03e4b6..0952546e 100644
--- a/app/backend/src/main/java/com/app/gamereview/service/UserService.java
+++ b/app/backend/src/main/java/com/app/gamereview/service/UserService.java
@@ -69,4 +69,10 @@ public Boolean deleteUserById(String id) {
return false;
}
+ public User getUserByEmail(String email) {
+ Optional getResult = userRepository.findByEmail(email);
+
+ return getResult.orElse(null);
+ }
+
}
diff --git a/app/backend/src/main/resources/.env.example b/app/backend/src/main/resources/.env.example
new file mode 100644
index 00000000..6eb48ecf
--- /dev/null
+++ b/app/backend/src/main/resources/.env.example
@@ -0,0 +1,10 @@
+MONGO_DATABASE=
+MONGO_USER=
+MONGO_PASSWORD=
+MONGO_CLUSTER=
+MAIL_HOST=
+MAIL_PORT=
+MAIL_USERNAME=
+MAIL_PASSWORD=
+MAIL_AUTH=
+MAIL_STARTTLS=
\ No newline at end of file
diff --git a/app/backend/src/main/resources/application.properties b/app/backend/src/main/resources/application.properties
index a7ba4c82..aefdd78c 100644
--- a/app/backend/src/main/resources/application.properties
+++ b/app/backend/src/main/resources/application.properties
@@ -1,2 +1,8 @@
spring.data.mongodb.database=${MONGO_DATABASE}
spring.data.mongodb.uri=mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}@${MONGO_CLUSTER}
+spring.mail.host=${MAIL_HOST}
+spring.mail.port=${MAIL_PORT}
+spring.mail.username=${MAIL_USERNAME}
+spring.mail.password=${MAIL_PASSWORD}
+spring.mail.properties.mail.smtp.auth=${MAIL_AUTH}
+spring.mail.properties.mail.smtp.starttls.enable=${MAIL_STARTTLS}
\ No newline at end of file
diff --git a/app/backend/target/classes/application.properties b/app/backend/target/classes/application.properties
index a7ba4c82..aefdd78c 100644
--- a/app/backend/target/classes/application.properties
+++ b/app/backend/target/classes/application.properties
@@ -1,2 +1,8 @@
spring.data.mongodb.database=${MONGO_DATABASE}
spring.data.mongodb.uri=mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}@${MONGO_CLUSTER}
+spring.mail.host=${MAIL_HOST}
+spring.mail.port=${MAIL_PORT}
+spring.mail.username=${MAIL_USERNAME}
+spring.mail.password=${MAIL_PASSWORD}
+spring.mail.properties.mail.smtp.auth=${MAIL_AUTH}
+spring.mail.properties.mail.smtp.starttls.enable=${MAIL_STARTTLS}
\ No newline at end of file