Skip to content

Commit

Permalink
Merge pull request ajaynegi45#89 from shreya5653/mybranch-shreya5653
Browse files Browse the repository at this point in the history
Implement Backend Functionality for Email Sending
  • Loading branch information
Guhapriya01 authored Oct 30, 2024
2 parents 1d26bac + 00779eb commit 664b333
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 144 deletions.
10 changes: 5 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,20 @@
<scope>runtime</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
Expand Down Expand Up @@ -93,13 +93,13 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableAsync
@EnableAsync(proxyTargetClass = true)
@EnableScheduling
@EnableCaching
@EnableCaching(proxyTargetClass = true)
public class LibrarymanApiApplication {

public static void main(String[] args) {
SpringApplication.run(LibrarymanApiApplication.class, args);
}

}
}
2 changes: 1 addition & 1 deletion src/main/java/com/libraryman_api/book/BookController.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,4 @@ public BookDto updateBook(@PathVariable int id, @RequestBody BookDto bookDtoDeta
public void deleteBook(@PathVariable int id) {
bookService.deleteBook(id);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -349,4 +349,4 @@ public BorrowingsDto EntityToDto(Borrowings borrowings) {
borrowingsDto.setBook(bookService.EntityToDto(borrowings.getBook()));
return borrowingsDto;
}
}
}
72 changes: 49 additions & 23 deletions src/main/java/com/libraryman_api/email/EmailService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/libraryman_api/member/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,4 @@ public MembersDto EntityToDto(Members members) {
membersDto.setMembershipDate(members.getMembershipDate());
return membersDto;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,44 +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.*;

import java.util.Map;

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

@Autowired
private NewsletterService newsletterService;
private final NewsletterService newsletterService;

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

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

// Call the service to handle subscription
String response = newsletterService.subscribe(email);
switch (result) {
case "Invalid email format.":
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result); // 400 Bad Request

// Return response from the service
if (response.equals("Invalid email format.") || response.equals("Email is already subscribed.")) {
return ResponseEntity.badRequest().body(response);
}
case "Email is already subscribed.":
return ResponseEntity.status(HttpStatus.CONFLICT).body(result); // 409 Conflict

return ResponseEntity.ok(response);
}
case "You have successfully subscribed!":
return ResponseEntity.status(HttpStatus.CREATED).body(result); // 201 Created

// Unsubscribe endpoint using token
@GetMapping("/unsubscribe/{token}")
public ResponseEntity<String> unsubscribe(@PathVariable String token) {
String response = newsletterService.unsubscribe(token);
case "You have successfully re-subscribed!":
return ResponseEntity.status(HttpStatus.OK).body(result); // 200 OK

// 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);
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.");
}
}

return ResponseEntity.ok(response);
// Unsubscribe Endpoint
@GetMapping("/unsubscribe")
public ResponseEntity<String> 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.");
}
}
}
Loading

0 comments on commit 664b333

Please sign in to comment.