diff --git a/pom.xml b/pom.xml
index 6a8c65e..683deaa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,20 +51,20 @@
runtime
true
-
+
io.jsonwebtoken
jjwt-api
0.11.5
-
+
io.jsonwebtoken
jjwt-impl
0.11.5
runtime
-
+
io.jsonwebtoken
jjwt-jackson
@@ -93,13 +93,13 @@
org.springframework.boot
spring-boot-starter-security
-
+
org.springframework.security
spring-security-test
test
-
+
org.springframework.security
spring-security-oauth2-client
diff --git a/src/main/java/com/libraryman_api/book/BookController.java b/src/main/java/com/libraryman_api/book/BookController.java
index 3cd3af3..0e2660f 100644
--- a/src/main/java/com/libraryman_api/book/BookController.java
+++ b/src/main/java/com/libraryman_api/book/BookController.java
@@ -100,4 +100,4 @@ public BookDto updateBook(@PathVariable int id, @RequestBody BookDto bookDtoDeta
public void deleteBook(@PathVariable int id) {
bookService.deleteBook(id);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/libraryman_api/borrowing/BorrowingService.java b/src/main/java/com/libraryman_api/borrowing/BorrowingService.java
index 6975e71..0b05b17 100644
--- a/src/main/java/com/libraryman_api/borrowing/BorrowingService.java
+++ b/src/main/java/com/libraryman_api/borrowing/BorrowingService.java
@@ -349,4 +349,4 @@ public BorrowingsDto EntityToDto(Borrowings borrowings) {
borrowingsDto.setBook(bookService.EntityToDto(borrowings.getBook()));
return borrowingsDto;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/libraryman_api/email/EmailService.java b/src/main/java/com/libraryman_api/email/EmailService.java
index f5f80b3..c59e644 100644
--- a/src/main/java/com/libraryman_api/email/EmailService.java
+++ b/src/main/java/com/libraryman_api/email/EmailService.java
@@ -17,62 +17,88 @@
import org.springframework.stereotype.Service;
/**
- * Service class for sending emails asynchronously.
- * This class handles the construction and sending of MIME email messages.
+ * Unified service class for sending emails asynchronously.
+ * Handles both general email sending and notifications.
*/
@Service
public class EmailService implements EmailSender {
private static final Logger LOGGER = LoggerFactory.getLogger(EmailService.class);
+
private final NotificationRepository notificationRepository;
private final JavaMailSender mailSender;
- @Value("${spring.mail.properties.domain_name}")
+
+ @Value("${spring.mail.properties.domain_name}") // Domain name from application properties
private String domainName;
- /**
- * Constructs a new {@code EmailService} with the specified {@link NotificationRepository} and {@link JavaMailSender}.
- *
- * @param notificationRepository the repository for managing notification entities
- * @param mailSender the mail sender for sending email messages
- */
public EmailService(NotificationRepository notificationRepository, JavaMailSender mailSender) {
this.notificationRepository = notificationRepository;
this.mailSender = mailSender;
}
/**
- * Sends an email asynchronously to the specified recipient.
- * If the email is successfully sent, the notification status is updated to SENT.
- * If the email fails to send, the notification status is updated to FAILED and an exception is thrown.
+ * Sends a general email asynchronously.
*
- * @param to the recipient's email address
- * @param email the content of the email to send
- * @param subject the subject of the email
- * @param notification the {@link Notifications} object representing the email notification
+ * @param to recipient's email
+ * @param body email content (HTML supported)
+ * @param subject subject of the email
*/
- @Override
@Async
- public void send(String to, String email, String subject, Notifications notification) {
+ public void sendEmail(String to, String body, String subject) {
+ sendEmail(to, body, subject, null); // Default 'from' to null
+ }
+
+ /**
+ * Sends a general email asynchronously.
+ *
+ * @param to recipient's email
+ * @param body email content (HTML supported)
+ * @param subject subject of the email
+ * @param from sender's email address (overrides default if provided)
+ */
+ @Async
+ public void sendEmail(String to, String body, String subject, String from) {
try {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, "utf-8");
- helper.setText(email, true);
+
+ helper.setText(body, true); // true = enable HTML content
helper.setTo(to);
helper.setSubject(subject);
- helper.setFrom(domainName);
+ helper.setFrom(from != null ? from : domainName); // Use provided sender or default domain
+
mailSender.send(mimeMessage);
+ } catch (MessagingException e) {
+ LOGGER.error("Failed to send email", e);
+ throw new IllegalStateException("Failed to send email", e);
+ }
+ }
+
+ /**
+ * Sends a notification email and updates notification status.
+ *
+ * @param to recipient's email
+ * @param email email content
+ * @param subject subject of the email
+ * @param notification notification entity to update status
+ */
+ @Override
+ @Async
+ public void send(String to, String email, String subject, Notifications notification) {
+ try {
+ sendEmail(to, email, subject); // Reuse sendEmail method for notifications
// Update notification status to SENT
notification.setNotificationStatus(NotificationStatus.SENT);
notificationRepository.save(notification);
- } catch (MessagingException e) {
- LOGGER.error("Failed to send email", e);
+ } catch (Exception e) {
+ LOGGER.error("Failed to send notification email", e);
// Update notification status to FAILED
notification.setNotificationStatus(NotificationStatus.FAILED);
notificationRepository.save(notification);
- throw new IllegalStateException("Failed to send email", e);
+ throw new IllegalStateException("Failed to send notification email", e);
}
}
}
diff --git a/src/main/java/com/libraryman_api/member/MemberService.java b/src/main/java/com/libraryman_api/member/MemberService.java
index 553d650..518b7f1 100644
--- a/src/main/java/com/libraryman_api/member/MemberService.java
+++ b/src/main/java/com/libraryman_api/member/MemberService.java
@@ -225,4 +225,4 @@ public MembersDto EntityToDto(Members members) {
membersDto.setMembershipDate(members.getMembershipDate());
return membersDto;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/libraryman_api/newsletter/EmailService1.java b/src/main/java/com/libraryman_api/newsletter/EmailService1.java
deleted file mode 100644
index b1f2086..0000000
--- a/src/main/java/com/libraryman_api/newsletter/EmailService1.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.libraryman_api.newsletter;
-
-
-import jakarta.mail.MessagingException;
-import jakarta.mail.internet.MimeMessage;
-import org.springframework.mail.javamail.JavaMailSender;
-import org.springframework.mail.javamail.MimeMessageHelper;
-import org.springframework.stereotype.Service;
-
-@Service
-public class EmailService1 {
-
- private final JavaMailSender mailSender;
-
- public EmailService1(JavaMailSender mailSender) {
- this.mailSender = mailSender;
- }
-
- public void send(String to, String body, String subject, Object notification) {
- try {
- MimeMessage mimeMessage = mailSender.createMimeMessage();
- MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, "utf-8");
- helper.setText(body, true);
- helper.setTo(to);
- helper.setSubject(subject);
- helper.setFrom("your-email@gmail.com");
- mailSender.send(mimeMessage);
- } catch (MessagingException e) {
- throw new IllegalStateException("Failed to send email", e);
- }
- }
-}
diff --git a/src/main/java/com/libraryman_api/newsletter/MailConfig.java b/src/main/java/com/libraryman_api/newsletter/MailConfig.java
deleted file mode 100644
index 37d1a55..0000000
--- a/src/main/java/com/libraryman_api/newsletter/MailConfig.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.libraryman_api.newsletter;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.mail.javamail.JavaMailSender;
-import org.springframework.mail.javamail.JavaMailSenderImpl;
-
-import java.util.Properties;
-
-@Configuration
-public class MailConfig {
-
- @Bean
- public JavaMailSender javaMailSender() {
- JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
- mailSender.setHost("smtp.gmail.com");
- mailSender.setPort(587);
- mailSender.setUsername("your-email@gmail.com");
- mailSender.setPassword("your-password");
-
- Properties props = mailSender.getJavaMailProperties();
- props.put("mail.transport.protocol", "smtp");
- props.put("mail.smtp.auth", "true");
- props.put("mail.smtp.starttls.enable", "true");
- return mailSender;
- }
-}
diff --git a/src/main/java/com/libraryman_api/newsletter/NewsletterController.java b/src/main/java/com/libraryman_api/newsletter/NewsletterController.java
index f454111..c1cbc8b 100644
--- a/src/main/java/com/libraryman_api/newsletter/NewsletterController.java
+++ b/src/main/java/com/libraryman_api/newsletter/NewsletterController.java
@@ -1,26 +1,71 @@
package com.libraryman_api.newsletter;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
-@RequestMapping("/newsletter")
+@RequestMapping("/api/newsletter")
public class NewsletterController {
private final NewsletterService newsletterService;
- @Autowired
public NewsletterController(NewsletterService newsletterService) {
this.newsletterService = newsletterService;
}
+ // Subscribe Endpoint
@PostMapping("/subscribe")
- public String subscribe(@RequestParam String email) {
- return newsletterService.subscribe(email);
+ public ResponseEntity subscribe(@RequestParam String email) {
+ try {
+ String result = newsletterService.subscribe(email);
+
+ switch (result) {
+ case "Invalid email format.":
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result); // 400 Bad Request
+
+ case "Email is already subscribed.":
+ return ResponseEntity.status(HttpStatus.CONFLICT).body(result); // 409 Conflict
+
+ case "You have successfully subscribed!":
+ return ResponseEntity.status(HttpStatus.CREATED).body(result); // 201 Created
+
+ case "You have successfully re-subscribed!":
+ return ResponseEntity.status(HttpStatus.OK).body(result); // 200 OK
+
+ default:
+ return ResponseEntity.status(HttpStatus.OK).body(result); // Default 200 OK
+ }
+ } catch (Exception e) {
+ // Handle unexpected errors
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body("An error occurred while processing your subscription.");
+ }
}
+ // Unsubscribe Endpoint
@GetMapping("/unsubscribe")
- public String unsubscribe(@RequestParam String token) {
- return newsletterService.unsubscribe(token);
+ public ResponseEntity unsubscribe(@RequestParam String token) {
+ try {
+ String result = newsletterService.unsubscribe(token);
+
+ switch (result) {
+ case "Invalid or expired token.":
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(result); // 404 Not Found
+
+ case "You are already unsubscribed.":
+ return ResponseEntity.status(HttpStatus.CONFLICT).body(result); // 409 Conflict
+
+ case "You have successfully unsubscribed!":
+ return ResponseEntity.status(HttpStatus.OK).body(result); // 200 OK
+
+ default:
+ return ResponseEntity.status(HttpStatus.OK).body(result); // Default 200 OK
+ }
+ } catch (Exception e) {
+ // Handle unexpected errors
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body("An error occurred while processing your unsubscription.");
+ }
}
}
diff --git a/src/main/java/com/libraryman_api/newsletter/NewsletterService.java b/src/main/java/com/libraryman_api/newsletter/NewsletterService.java
index ea19e7d..5c12cd1 100644
--- a/src/main/java/com/libraryman_api/newsletter/NewsletterService.java
+++ b/src/main/java/com/libraryman_api/newsletter/NewsletterService.java
@@ -60,14 +60,17 @@ private boolean isValidEmail(String email) {
private void sendSubscriptionEmail(String email, String token) {
String subject = "Welcome to Our Newsletter!";
- String body = "Thank you for subscribing! To unsubscribe, click the link:\n" +
- "http://localhost:8080/newsletter/unsubscribe?token=" + token;
- emailService.send(email, body, subject, null);
+ String body = "Thank you for subscribing! " +
+ "To unsubscribe, click the link:\n" +
+ "http://localhost:8080/api/newsletter/unsubscribe?token=" + token;
+
+ emailService.sendEmail(email, body, subject); // No need to change this line
}
private void sendUnsubscribeEmail(String email) {
String subject = "You have been unsubscribed";
String body = "You have successfully unsubscribed. If this was a mistake, you can re-subscribe.";
- emailService.send(email, body, subject, null);
+
+ emailService.sendEmail(email, body, subject); // No need to change this line
}
}
diff --git a/src/main/java/com/libraryman_api/security/config/WebConfiguration.java b/src/main/java/com/libraryman_api/security/config/WebConfiguration.java
index 61b4002..413db45 100644
--- a/src/main/java/com/libraryman_api/security/config/WebConfiguration.java
+++ b/src/main/java/com/libraryman_api/security/config/WebConfiguration.java
@@ -86,4 +86,4 @@ public CorsFilter corsFilter() {
return new CorsFilter(corsConfigurationSource());
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/libraryman_api/security/services/SignupService.java b/src/main/java/com/libraryman_api/security/services/SignupService.java
index cb7bb64..4d6b0e8 100644
--- a/src/main/java/com/libraryman_api/security/services/SignupService.java
+++ b/src/main/java/com/libraryman_api/security/services/SignupService.java
@@ -84,4 +84,4 @@ public void signupLibrarian(Members members) {
new_members.setUsername(members.getUsername());
memberRepository.save(new_members);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/resources/application-development.properties b/src/main/resources/application-development.properties
index a1b8ca0..4deec9c 100644
--- a/src/main/resources/application-development.properties
+++ b/src/main/resources/application-development.properties
@@ -40,4 +40,12 @@ spring.mail.username=Add_Your_Mail_Service_Username
spring.mail.password=Add_Your_Mail_Service_Password
spring.mail.properties.mail.smtp.auth=Add_Your_Mail_Service_SMTP
spring.mail.properties.mail.starttls.enable=Add_Your_Mail_Service_Start_TLS
-spring.mail.properties.domain_name=Add_Your_Mail_Service_Domain_Name
\ No newline at end of file
+spring.mail.properties.domain_name=Add_Your_Mail_Service_Domain_Name
+
+
+
+# --- Oauth 2.0 Configurations ---
+spring.security.oauth2.client.registration.google.client-name=google
+spring.security.oauth2.client.registration.google.client-id=ADD_YOUR_CLIENT_ID
+spring.security.oauth2.client.registration.google.client-secret=ADD_YOUR_SECRET_KEY
+spring.security.oauth2.client.registration.google.scope=email,profile
\ No newline at end of file