diff --git a/src/main/java/com/libraryman_api/newsletter/NewsletterController.java b/src/main/java/com/libraryman_api/newsletter/NewsletterController.java new file mode 100644 index 0000000..fe038fe --- /dev/null +++ b/src/main/java/com/libraryman_api/newsletter/NewsletterController.java @@ -0,0 +1,44 @@ +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") +public class NewsletterController { + + @Autowired + private NewsletterService newsletterService; + + // Subscribe endpoint + @PostMapping("/subscribe") + public ResponseEntity subscribe(@RequestBody Map 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); + } + + // Unsubscribe endpoint using token + @GetMapping("/unsubscribe/{token}") + public ResponseEntity 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); + } +} diff --git a/src/main/java/com/libraryman_api/newsletter/NewsletterService.java b/src/main/java/com/libraryman_api/newsletter/NewsletterService.java new file mode 100644 index 0000000..034fd78 --- /dev/null +++ b/src/main/java/com/libraryman_api/newsletter/NewsletterService.java @@ -0,0 +1,74 @@ +package com.libraryman_api.newsletter; + +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 { + + @Autowired + private NewsletterSubscriberRepository subscriberRepository; + + // Subscribe user after validating email + public String subscribe(String email) { + if (!isValidEmail(email)) { + return "Invalid email format."; + } + + // Check if the email already exists + Optional 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 + return "You have successfully re-subscribed!"; + } else { + return "Email is already subscribed."; + } + } + + // Save new subscriber if not present + NewsletterSubscriber subscriber = new NewsletterSubscriber(email); + subscriberRepository.save(subscriber); + return "You have successfully subscribed!"; + } + + // Unsubscribe user using the token + public String unsubscribe(String token) { + Optional optionalSubscriber = subscriberRepository.findByUnsubscribeToken(token); + + if (optionalSubscriber.isEmpty()) { + return "Invalid or expired token."; + } + + NewsletterSubscriber subscriber = optionalSubscriber.get(); + + if (!subscriber.isActive()) { + return "You are already unsubscribed."; + } + + subscriber.setActive(false); // Set active to false + subscriberRepository.save(subscriber); // Save the updated subscriber + 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(); + } +} diff --git a/src/main/java/com/libraryman_api/newsletter/NewsletterSubscriber.java b/src/main/java/com/libraryman_api/newsletter/NewsletterSubscriber.java new file mode 100644 index 0000000..75412b5 --- /dev/null +++ b/src/main/java/com/libraryman_api/newsletter/NewsletterSubscriber.java @@ -0,0 +1,67 @@ +package com.libraryman_api.newsletter; + +import jakarta.persistence.*; +import java.util.UUID; + +@Entity +@Table(name = "newsletter_subscribers") +public class NewsletterSubscriber { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, unique = true) + private String email; + + @Column(nullable = false) + private boolean active = true; // Manage subscription status + + @Column(name = "unsubscribe_token", nullable = false, unique = true) + private String unsubscribeToken; // Token for unsubscribing + + // Default constructor that initializes the token + public NewsletterSubscriber() { + this.unsubscribeToken = UUID.randomUUID().toString(); // Generate token by default + } + + // Constructor to initialize 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(); + } +} diff --git a/src/main/java/com/libraryman_api/newsletter/NewsletterSubscriberRepository.java b/src/main/java/com/libraryman_api/newsletter/NewsletterSubscriberRepository.java new file mode 100644 index 0000000..1e6d215 --- /dev/null +++ b/src/main/java/com/libraryman_api/newsletter/NewsletterSubscriberRepository.java @@ -0,0 +1,14 @@ +package com.libraryman_api.newsletter; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface NewsletterSubscriberRepository extends JpaRepository { + + // Find a subscriber by email + Optional findByEmail(String email); + + // Find a subscriber by unsubscribe token + Optional findByUnsubscribeToken(String unsubscribeToken); +}