Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Empty file added curl
Empty file.
20 changes: 16 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>2.14.0.RELEASE</version>

</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>


</dependencies>
<dependencyManagement>
<dependencies>
Expand Down Expand Up @@ -139,11 +153,9 @@
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protobuf-java.version}:exe:${os.detected.classifier}
</protocArtifact>
<protocArtifact>com.google.protobuf:protoc:${protobuf-java.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
</pluginArtifact>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.uguimar.notificationsms.application.port.input;

import reactor.core.publisher.Mono;

public interface SendVerificationEmailUseCase {
Mono<Void> send(String toEmail, String code);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.uguimar.notificationsms.application.port.output;

import com.uguimar.notificationsms.domain.model.Email;
import reactor.core.publisher.Mono;

public interface EmailSender {
Mono<Void> sendEmail(Email email);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package com.uguimar.notificationsms.application.service;
//Este archivo interactua con JavaEmailTest
//Servicio Usado JavaEmail

import com.uguimar.notificationsms.application.port.output.EmailSender;
import com.uguimar.notificationsms.domain.model.Email;
import com.uguimar.notificationsms.domain.exception.EmailSendingException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;

import reactor.core.publisher.Mono;

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;

import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

//Servicio para el envío de correos electrónicos utilizando JavaMailSender
//Implementa la interfaz EmailSender para proporcionar funcionalidad de envío de emails
@Service
public class JavaEmailService implements EmailSender {
private static final Logger logger = LoggerFactory.getLogger(JavaEmailService.class);

// Componente para el envío de emails proporcionado por Spring
private final JavaMailSender mailSender;
// Email del remitente configurado en application.properties
private final String fromEmail;
// Plantilla HTML del email cargada al iniciar el servicio
private final String emailTemplate;


//Constructor del servicio
public JavaEmailService(JavaMailSender mailSender,
@Value("${spring.mail.username}") String fromEmail) {
this.mailSender = mailSender;
this.fromEmail = fromEmail;
try {
// Carga la plantilla HTML al iniciar el servicio
this.emailTemplate = loadEmailTemplate();
logger.info("Email template loaded successfully");
} catch (IOException e) {
String errorMsg = "Failed to load email template";
logger.error(errorMsg, e);
throw new EmailSendingException(errorMsg, e);
}
}

//Envía un email de forma reactiva.
@Override
public Mono<Void> sendEmail(Email email) {
if (email == null) {
return Mono.error(new IllegalArgumentException("Email cannot be null"));
}

return Mono.fromRunnable(() -> {
try {
validateEmailFields(email);
sendMimeEmail(email);
} catch (MessagingException e) {
handleEmailSendingError(email, e);
}
});
}

//Valida los campos obligatorios del email.
private void validateEmailFields(Email email) {
if (email.getTo() == null || email.getTo().isBlank()) {
throw new IllegalArgumentException("Recipient email address cannot be empty");
}
if (email.getSubject() == null || email.getSubject().isBlank()) {
throw new IllegalArgumentException("Email subject cannot be empty");
}
if (email.getCode() == null) {
throw new IllegalArgumentException("Email code cannot be null");
}
}

//Construye y envía el email MIME.
private void sendMimeEmail(Email email) throws MessagingException {
logger.debug("Preparing to send email to {}", email.getTo());

MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);

helper.setFrom(fromEmail);
helper.setTo(email.getTo());
helper.setSubject(email.getSubject());
helper.setText(buildEmailContent(email.getCode()), true); // false indica texto plano //true indica HTML

mailSender.send(message);
logger.info("Email successfully sent to {}", email.getTo());
}

//Maneja errores durante el envío del email.
private void handleEmailSendingError(Email email, MessagingException e) {
String errorMessage = String.format("Failed to send email to %s. Reason: %s",
email.getTo(), e.getMessage());
logger.error(errorMessage, e);
throw new EmailSendingException(errorMessage, e);
}

//Carga la plantilla HTML desde los recursos.
private String loadEmailTemplate() throws IOException {
ClassPathResource resource = new ClassPathResource("Templates/TextMail.html");
try (InputStreamReader reader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)) {
return FileCopyUtils.copyToString(reader);
}
}

//Reemplaza el placeholder en la plantilla con el codigo de verificacion
private String buildEmailContent(String code) {
return emailTemplate.replace("${code}", code);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.uguimar.notificationsms.application.service;

import org.springframework.stereotype.Service;

import com.uguimar.notificationsms.application.port.input.SendVerificationEmailUseCase;
import com.uguimar.notificationsms.application.port.output.EmailSender;
import com.uguimar.notificationsms.domain.model.Email;
import reactor.core.publisher.Mono;

@Service //Para el gRPC service
public class SendVerificationEmailService implements SendVerificationEmailUseCase {
private final EmailSender emailSender;

public SendVerificationEmailService(EmailSender emailSender) {
this.emailSender = emailSender;
}

@Override
public Mono<Void> send(String toEmail, String code) {
String subject = "Código de verificación";
String body = "Tu código de verificación es: " + code;
Email email = new Email(toEmail, subject, body);
return emailSender.sendEmail(email);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.uguimar.notificationsms.controler;

import com.uguimar.notificationsms.domain.model.Email;
import com.uguimar.notificationsms.application.port.output.EmailSender;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

//Controlador REST para enviar correos de prueba
@RestController
@RequestMapping("/test-email")
public class TestJavaEmailController {

@Autowired
private EmailSender emailSender;

//Endpoint POST para enviar correo de prueba (probado con postman y en la terminal)
@PostMapping
public Mono<String> sendTestEmail() {
// Datos de prueba - Reemplazar con valores reales para testing
Email email = new Email(
"example@correo.com", // correo para el destinatario deben cambiarlo por un correo suyo en caso de querer probarlo como test
"Asunto de prueba",
"COD123"
);
return emailSender.sendEmail(email)
.thenReturn("Correo enviado con éxito");
}

//Endpoint de verificación de estado del servicio
@GetMapping("/check")
public String check() {
return "Servicio REST activo (puerto 8080) | gRPC en 9090";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.uguimar.notificationsms.domain.exception;

//Excepción personalizada que se lanza cuando ocurre un error al enviar un correo
public class EmailSendingException extends RuntimeException {
public EmailSendingException(String message) {
super(message);
}
public EmailSendingException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.uguimar.notificationsms.domain.exception;

public class InvalidEmailException extends RuntimeException {
public InvalidEmailException(String message) {
super(message);
}
}

This file was deleted.

40 changes: 40 additions & 0 deletions src/main/java/com/uguimar/notificationsms/domain/model/Email.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.uguimar.notificationsms.domain.model;

public class Email {
private String to;
private String subject;
private String code;

public Email(String to, String subject, String code) {
this.to = to;
this.subject = subject;
this.code = code;
}

public Email(){
}

public String getTo() {
return to;
}

public void setTo(String to) {
this.to = to;
}

public String getSubject() {
return subject;
}

public void setSubject(String subject) {
this.subject = subject;
}

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.uguimar.notificationsms.infrastructure.input.grpc;


import io.grpc.stub.StreamObserver;
import reactor.core.publisher.Mono;

import org.springframework.grpc.server.service.GrpcService;

import com.uguimar.notificationsms.application.port.input.SendVerificationEmailUseCase;
import com.uguimar.notificationsms.grpc.NotificationServiceGrpc;
import com.uguimar.notificationsms.grpc.SendNotificationEmailRequest;
import com.uguimar.notificationsms.grpc.SendNotificationEmailResponse;
@GrpcService //Notacion para el servivio gRPC
public class NotificationGrpcService extends NotificationServiceGrpc.NotificationServiceImplBase {

//Creamos el atributo del servicio
private final SendVerificationEmailUseCase sendVerificationEmailUseCase;

//Constructor del servicio
public NotificationGrpcService(SendVerificationEmailUseCase sendVerificationEmailUseCase) {
this.sendVerificationEmailUseCase = sendVerificationEmailUseCase;
}

//Sobreescribimos el metodo del gRPC
@Override
public void sendNotificationEmail(SendNotificationEmailRequest request, StreamObserver<SendNotificationEmailResponse> responseObserver) {

Mono<Void> result = sendVerificationEmailUseCase.send(request.getEmail(), request.getCode());

//Ejecutamos el servicio
result.subscribe(
//Si todo logra ejecutarse bien envia un true
unused -> {
SendNotificationEmailResponse response = SendNotificationEmailResponse.newBuilder()
.setSuccess(true)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
},
//Si no se ejecuta bien o algo falla envia un false
error -> {
SendNotificationEmailResponse response = SendNotificationEmailResponse.newBuilder()
.setSuccess(false)
.build ();
responseObserver.onNext( response );
responseObserver.onCompleted();
}
);
}

}
Loading