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

Implement Backend Functionality for Email Sending #89

Merged
merged 5 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
32 changes: 32 additions & 0 deletions src/main/java/com/libraryman_api/newsletter/EmailService1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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("[email protected]");
mailSender.send(mimeMessage);
} catch (MessagingException e) {
throw new IllegalStateException("Failed to send email", e);
}
}
}
27 changes: 27 additions & 0 deletions src/main/java/com/libraryman_api/newsletter/MailConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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("[email protected]");
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;
}
}
Original file line number Diff line number Diff line change
@@ -1,44 +1,26 @@
package com.libraryman_api.newsletter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
@RequestMapping("/api/newsletter")
@RequestMapping("/newsletter")
public class NewsletterController {

private final NewsletterService newsletterService;

@Autowired
private NewsletterService newsletterService;
public NewsletterController(NewsletterService newsletterService) {
this.newsletterService = newsletterService;
}

// Subscribe endpoint
@PostMapping("/subscribe")
public ResponseEntity<String> subscribe(@RequestBody Map<String, String> requestBody) {
String email = requestBody.get("email");

// Call the service to handle subscription
String response = newsletterService.subscribe(email);

// Return response from the service
if (response.equals("Invalid email format.") || response.equals("Email is already subscribed.")) {
return ResponseEntity.badRequest().body(response);
}

return ResponseEntity.ok(response);
public String subscribe(@RequestParam String email) {
return newsletterService.subscribe(email);
}

// Unsubscribe endpoint using token
@GetMapping("/unsubscribe/{token}")
public ResponseEntity<String> unsubscribe(@PathVariable String token) {
String response = newsletterService.unsubscribe(token);

// Check if the response indicates an error
if (response.equals("Invalid or expired token.") || response.equals("You are already unsubscribed.")) {
return ResponseEntity.badRequest().body(response);
}

return ResponseEntity.ok(response);
@GetMapping("/unsubscribe")
public String unsubscribe(@RequestParam String token) {
return newsletterService.unsubscribe(token);
}
}
73 changes: 36 additions & 37 deletions src/main/java/com/libraryman_api/newsletter/NewsletterService.java
Original file line number Diff line number Diff line change
@@ -1,74 +1,73 @@
package com.libraryman_api.newsletter;

import com.libraryman_api.email.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class NewsletterService {

private final NewsletterSubscriberRepository subscriberRepository;
private final EmailService emailService;

@Autowired
private NewsletterSubscriberRepository subscriberRepository;
public NewsletterService(NewsletterSubscriberRepository subscriberRepository, EmailService emailService) {
this.subscriberRepository = subscriberRepository;
this.emailService = emailService;
}

// Subscribe user after validating email
public String subscribe(String email) {
if (!isValidEmail(email)) {
return "Invalid email format.";
}
if (!isValidEmail(email)) return "Invalid email format.";

// Check if the email already exists
Optional<NewsletterSubscriber> optionalSubscriber = subscriberRepository.findByEmail(email);

if (optionalSubscriber.isPresent()) {
NewsletterSubscriber subscriber = optionalSubscriber.get();

// If the subscriber is inactive, reactivate them
if (!subscriber.isActive()) {
subscriber.setActive(true); // Reactivate the subscriber
subscriber.regenerateToken(); // Generate a new token
subscriberRepository.save(subscriber); // Save the updated subscriber
subscriber.setActive(true);
subscriber.regenerateToken();
subscriberRepository.save(subscriber);
sendSubscriptionEmail(email, subscriber.getUnsubscribeToken());
return "You have successfully re-subscribed!";
} else {
return "Email is already subscribed.";
}
return "Email is already subscribed.";
}

// Save new subscriber if not present
NewsletterSubscriber subscriber = new NewsletterSubscriber(email);
subscriberRepository.save(subscriber);
NewsletterSubscriber newSubscriber = new NewsletterSubscriber(email);
subscriberRepository.save(newSubscriber);
sendSubscriptionEmail(email, newSubscriber.getUnsubscribeToken());
return "You have successfully subscribed!";
}

// Unsubscribe user using the token
public String unsubscribe(String token) {
Optional<NewsletterSubscriber> optionalSubscriber = subscriberRepository.findByUnsubscribeToken(token);

if (optionalSubscriber.isEmpty()) {
return "Invalid or expired token.";
}
if (optionalSubscriber.isEmpty()) return "Invalid or expired token.";

NewsletterSubscriber subscriber = optionalSubscriber.get();
if (!subscriber.isActive()) return "You are already unsubscribed.";

if (!subscriber.isActive()) {
return "You are already unsubscribed.";
}

subscriber.setActive(false); // Set active to false
subscriberRepository.save(subscriber); // Save the updated subscriber
subscriber.setActive(false);
subscriberRepository.save(subscriber);
sendUnsubscribeEmail(subscriber.getEmail());
return "You have successfully unsubscribed!";
}

// Email validation logic
private boolean isValidEmail(String email) {
if (email == null || email.trim().isEmpty()) {
return false;
}
String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
Pattern pattern = Pattern.compile(emailRegex);
Matcher matcher = pattern.matcher(email);
return matcher.matches();
return Pattern.compile(emailRegex).matcher(email).matches();
}

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);
}

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);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.libraryman_api.newsletter;

import jakarta.persistence.*;

import java.util.UUID;

@Entity
Expand All @@ -16,53 +15,28 @@ public class NewsletterSubscriber {
private String email;

@Column(nullable = false)
private boolean active = true; // Manage subscription status
private boolean active = true;

@Column(name = "unsubscribe_token", nullable = false, unique = true)
private String unsubscribeToken; // Token for unsubscribing
private String unsubscribeToken;

// Default constructor that initializes the token
// Default constructor initializing unsubscribe token
public NewsletterSubscriber() {
this.unsubscribeToken = UUID.randomUUID().toString(); // Generate token by default
this.unsubscribeToken = UUID.randomUUID().toString();
}

// Constructor to initialize with email
// Constructor initializing with email
public NewsletterSubscriber(String email) {
this();
this.email = email;
}

// Getters and setters
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public boolean isActive() {
return active;
}

public void setActive(boolean active) {
this.active = active;
}

public String getUnsubscribeToken() {
return unsubscribeToken;
}

// Method to regenerate a new token
public void regenerateToken() {
this.unsubscribeToken = UUID.randomUUID().toString();
}
// Getters and Setters
public Long getId() { return id; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public boolean isActive() { return active; }
public void setActive(boolean active) { this.active = active; }
public String getUnsubscribeToken() { return unsubscribeToken; }
public void regenerateToken() { this.unsubscribeToken = UUID.randomUUID().toString(); }
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package com.libraryman_api.newsletter;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface NewsletterSubscriberRepository extends JpaRepository<NewsletterSubscriber, Long> {

// Find a subscriber by email
Optional<NewsletterSubscriber> findByEmail(String email);

// Find a subscriber by unsubscribe token
Optional<NewsletterSubscriber> findByUnsubscribeToken(String unsubscribeToken);
}
4 changes: 1 addition & 3 deletions src/main/resources/application-development.properties
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@ 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



# --- 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
spring.security.oauth2.client.registration.google.scope=email,profile
Loading